Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
5e5a835792 | |||
2523b32d19 | |||
2967465193 | |||
73fcd296fd | |||
4d4e6c7970 | |||
961f83badb | |||
d05d283354 | |||
1fd09cb653 | |||
1f07c1562d | |||
4eaedbfef6 | |||
f3a2d6486c | |||
f13551a529 | |||
d4db887d5a | |||
498ad25ccd | |||
09432848ce | |||
d9445d0deb | |||
3db988b553 | |||
fb71e75ef5 | |||
0a6ddb4d71 |
70
.drone.yml
70
.drone.yml
@ -1,42 +1,74 @@
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: default-linux-amd64
|
||||
name: build-linux
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
- name: build-linux-amd64
|
||||
image: golang
|
||||
commands:
|
||||
- ./ci-build.sh build
|
||||
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
||||
environment:
|
||||
GOOS: linux
|
||||
GOARCH: amd64
|
||||
- name: release
|
||||
image: plugins/gitea-release
|
||||
settings:
|
||||
base_url: https://git.paulbsd.com
|
||||
api_key:
|
||||
from_secret: gitea_token
|
||||
files: "*.tar.gz"
|
||||
checksum:
|
||||
- sha256
|
||||
- sha512
|
||||
GOOPTIONS: -mod=vendor
|
||||
SRCFILES: cmd/coronafana/*.go
|
||||
PROJECTNAME: coronafana
|
||||
when:
|
||||
event: tag
|
||||
event:
|
||||
exclude:
|
||||
- tag
|
||||
- name: build-linux-arm64
|
||||
image: golang
|
||||
commands:
|
||||
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
||||
environment:
|
||||
GOOS: linux
|
||||
GOARCH: arm64
|
||||
GOOPTIONS: -mod=vendor
|
||||
SRCFILES: cmd/coronafana/*.go
|
||||
PROJECTNAME: coronafana
|
||||
when:
|
||||
event:
|
||||
exclude:
|
||||
- tag
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: default-linux-arm64
|
||||
name: gitea-release-linux
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
- name: build-linux-amd64
|
||||
image: golang
|
||||
commands:
|
||||
- ./ci-build.sh build
|
||||
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
||||
- tar -czvf $PROJECTNAME-$DRONE_TAG-$GOOS-$GOARCH.tar.gz $PROJECTNAME
|
||||
- echo $PROJECTNAME $DRONE_TAG > VERSION
|
||||
environment:
|
||||
GOOS: linux
|
||||
GOARCH: amd64
|
||||
GOOPTIONS: -mod=vendor
|
||||
SRCFILES: cmd/coronafana/*.go
|
||||
PROJECTNAME: coronafana
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
- name: build-linux-arm64
|
||||
image: golang
|
||||
commands:
|
||||
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
||||
- tar -czvf $PROJECTNAME-$DRONE_TAG-$GOOS-$GOARCH.tar.gz $PROJECTNAME
|
||||
- echo $PROJECTNAME $DRONE_TAG > VERSION
|
||||
environment:
|
||||
GOOS: linux
|
||||
GOARCH: arm64
|
||||
GOOPTIONS: -mod=vendor
|
||||
SRCFILES: cmd/coronafana/*.go
|
||||
PROJECTNAME: coronafana
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
- name: release
|
||||
image: plugins/gitea-release
|
||||
settings:
|
||||
@ -47,5 +79,7 @@ steps:
|
||||
checksum:
|
||||
- sha256
|
||||
- sha512
|
||||
title: VERSION
|
||||
when:
|
||||
event: tag
|
||||
event:
|
||||
- tag
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,3 +2,5 @@
|
||||
/*.ini
|
||||
/*.json
|
||||
/dist
|
||||
/data-dir*
|
||||
*.swp
|
||||
|
19
Makefile
19
Makefile
@ -1,19 +0,0 @@
|
||||
# coronafana Makefile
|
||||
|
||||
GOCMD=go
|
||||
GOBUILDCMD=${GOCMD} build
|
||||
GOOPTIONS=-mod=vendor -ldflags="-s -w"
|
||||
PACKRCMD=${GOPATH}/bin/packr2
|
||||
|
||||
RMCMD=rm
|
||||
BINNAME=coronafana
|
||||
|
||||
SRCFILES=cmd/coronafana/*.go
|
||||
|
||||
all: build
|
||||
|
||||
build:
|
||||
${GOBUILDCMD} ${GOOPTIONS} ${SRCFILES}
|
||||
|
||||
clean:
|
||||
${RMCMD} -f ${BINNAME}
|
@ -1,4 +1,5 @@
|
||||
# coronafana
|
||||
[![Build Status](https://drone.paulbsd.com/api/badges/paulbsd/coronafana/status.svg)](https://drone.paulbsd.com/paulbsd/coronafana)
|
||||
|
||||
## Summary
|
||||
|
||||
@ -35,7 +36,7 @@ corona_url="https://coronavirus.politologue.com/data/coronavirus/coronacsv.aspx?
|
||||
|
||||
## License
|
||||
```text
|
||||
Copyright (c) 2020, PaulBSD
|
||||
Copyright (c) 2020 PaulBSD
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -61,4 +62,4 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of this project.
|
||||
```
|
||||
```
|
||||
|
44
ci-build.sh
44
ci-build.sh
@ -1,44 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
PROJECTNAME=coronafana
|
||||
RELEASENAME=${PROJECTNAME}
|
||||
VERSION="0"
|
||||
|
||||
GOOPTIONS="-mod=vendor"
|
||||
SRCFILES=cmd/coronafana/*.go
|
||||
|
||||
build() {
|
||||
if [[ ! -z $DRONE_TAG ]]
|
||||
then
|
||||
VERSION=$DRONE_TAG
|
||||
elif [[ ! -z $DRONE_TAG ]]
|
||||
then
|
||||
VERSION=$DRONE_COMMIT
|
||||
fi
|
||||
|
||||
if [[ ! -z $VERSION && ! -z $GOOS && ! -z $GOARCH ]]
|
||||
then
|
||||
RELEASENAME=${PROJECTNAME}-${VERSION}-${GOOS}-${GOARCH}
|
||||
fi
|
||||
go build -o ${PROJECTNAME} ${GOOPTIONS} ${SRCFILES}
|
||||
if [[ ! -z $DRONE_TAG ]]
|
||||
then
|
||||
tar -czvf ${RELEASENAME}.tar.gz ${PROJECTNAME}
|
||||
fi
|
||||
rm ${PROJECTNAME}
|
||||
}
|
||||
|
||||
clean() {
|
||||
rm -rf $RELEASEDIR
|
||||
}
|
||||
|
||||
case $1 in
|
||||
"build")
|
||||
build
|
||||
;;
|
||||
"clean")
|
||||
clean
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"git.paulbsd.com/paulbsd/coronafana/src/config"
|
||||
"git.paulbsd.com/paulbsd/coronafana/src/coronafana"
|
||||
"git.paulbsd.com/paulbsd/coronafana/src/network"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
@ -27,39 +28,54 @@ func main() {
|
||||
cfg.DbHostname,
|
||||
cfg.DbName))
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = db.Exec(cfg.DbSchemaGlobal)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = db.Exec(cfg.DbSchemaPays)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
cr, err = coronafana.GetData(cfg)
|
||||
tr, dialer, dialerctx, err := network.InitTorSession()
|
||||
defer dialerctx()
|
||||
defer tr.Close()
|
||||
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
cr, err = coronafana.GetData(cfg, dialer)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = cr.GetMaxDates(cfg, *db)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Processes data for 'Global'
|
||||
err = cr.InsertGlobalData(cfg, *db)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Processes data for 'Pays'
|
||||
err = cr.InsertPaysData(cfg, *db)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
23
go.mod
23
go.mod
@ -1,11 +1,22 @@
|
||||
module git.paulbsd.com/paulbsd/coronafana
|
||||
|
||||
go 1.14
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/jinzhu/gorm v1.9.12
|
||||
github.com/jmoiron/sqlx v1.2.0
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
gopkg.in/ini.v1 v1.54.0
|
||||
github.com/cretz/bine v0.2.0
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/denisenkom/go-mssqldb v0.12.3 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.1
|
||||
github.com/jinzhu/gorm v1.9.16
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/jmoiron/sqlx v1.3.5
|
||||
github.com/lib/pq v1.10.7 // indirect
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
||||
golang.org/x/crypto v0.13.0 // indirect
|
||||
golang.org/x/net v0.15.0 // indirect
|
||||
golang.org/x/sys v0.12.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
require github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
|
117
go.sum
117
go.sum
@ -1,48 +1,103 @@
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw=
|
||||
github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q=
|
||||
github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs=
|
||||
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
|
||||
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
|
||||
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
|
||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
||||
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw=
|
||||
github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
|
||||
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd h1:GGJVjV8waZKRHrgwvtH66z9ZGVurTD1MT0n1Bb+q4aM=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
gopkg.in/ini.v1 v1.54.0 h1:oM5ElzbIi7gwLnNbPX2M25ED1vSAK3B6dex50eS/6Fs=
|
||||
gopkg.in/ini.v1 v1.54.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
@ -3,20 +3,21 @@ package coronafana
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.paulbsd.com/paulbsd/coronafana/src/config"
|
||||
"github.com/cretz/bine/tor"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
// GetData fetch data from open data portal
|
||||
func GetData(cfg config.Config) (cr Coronafana, err error) {
|
||||
var client http.Client
|
||||
func GetData(cfg config.Config, d *tor.Dialer) (cr Coronafana, err error) {
|
||||
var client = &http.Client{Transport: &http.Transport{DialContext: d.DialContext}}
|
||||
|
||||
log.Println("Getting JSON file ...")
|
||||
|
||||
@ -30,7 +31,7 @@ func GetData(cfg config.Config) (cr Coronafana, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -71,7 +72,7 @@ func (cr Coronafana) InsertGlobalData(cfg config.Config, db sqlx.DB) (err error)
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
log.Println(fmt.Sprintf("%d global entries to inserted", i))
|
||||
log.Println(fmt.Sprintf("%d global entries to insert", i))
|
||||
} else {
|
||||
log.Println("No entry inserted")
|
||||
}
|
||||
@ -106,7 +107,7 @@ func (cr Coronafana) InsertPaysData(cfg config.Config, db sqlx.DB) (err error) {
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
log.Println(fmt.Sprintf("%d global entries to inserted", i))
|
||||
log.Println(fmt.Sprintf("%d global entries to insert", i))
|
||||
} else {
|
||||
log.Println("No entry inserted")
|
||||
}
|
||||
|
25
src/network/main.go
Normal file
25
src/network/main.go
Normal file
@ -0,0 +1,25 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/cretz/bine/tor"
|
||||
)
|
||||
|
||||
// InitTorSession initialize a tor session
|
||||
func InitTorSession() (t *tor.Tor, dialer *tor.Dialer, dialCancel context.CancelFunc, err error) {
|
||||
t, err = tor.Start(nil, nil)
|
||||
if err != nil {
|
||||
log.Panicf("Failed to start tor: %v", err)
|
||||
}
|
||||
// Wait at most a minute to start network and get
|
||||
dialCtx, dialCancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
|
||||
dialer, err = t.Dialer(dialCtx, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
21
vendor/github.com/cretz/bine/LICENSE
generated
vendored
Normal file
21
vendor/github.com/cretz/bine/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Chad Retz
|
||||
|
||||
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.
|
108
vendor/github.com/cretz/bine/control/cmd_authenticate.go
generated
vendored
Normal file
108
vendor/github.com/cretz/bine/control/cmd_authenticate.go
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
package control
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Authenticate authenticates with the Tor instance using the "best" possible
|
||||
// authentication method if not already authenticated and sets the Authenticated
|
||||
// field. The password argument is optional, and will only be used if the
|
||||
// "SAFECOOKIE" and "NULL" authentication methods are not available and
|
||||
// "HASHEDPASSWORD" is.
|
||||
func (c *Conn) Authenticate(password string) error {
|
||||
if c.Authenticated {
|
||||
return nil
|
||||
}
|
||||
// Determine the supported authentication methods, and the cookie path.
|
||||
pi, err := c.ProtocolInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Get the bytes to pass to with authenticate
|
||||
var authBytes []byte
|
||||
if pi.HasAuthMethod("NULL") {
|
||||
// No auth bytes
|
||||
} else if pi.HasAuthMethod("SAFECOOKIE") {
|
||||
if pi.CookieFile == "" {
|
||||
return c.protoErr("Invalid (empty) COOKIEFILE")
|
||||
}
|
||||
cookie, err := ioutil.ReadFile(pi.CookieFile)
|
||||
if err != nil {
|
||||
return c.protoErr("Failed to read COOKIEFILE: %v", err)
|
||||
} else if len(cookie) != 32 {
|
||||
return c.protoErr("Invalid cookie file length: %v", len(cookie))
|
||||
}
|
||||
|
||||
// Send an AUTHCHALLENGE command, and parse the response.
|
||||
var clientNonce [32]byte
|
||||
if _, err := rand.Read(clientNonce[:]); err != nil {
|
||||
return c.protoErr("Failed to generate clientNonce: %v", err)
|
||||
}
|
||||
resp, err := c.SendRequest("AUTHCHALLENGE %s %s", "SAFECOOKIE", hex.EncodeToString(clientNonce[:]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
splitResp := strings.Split(resp.Reply, " ")
|
||||
if len(splitResp) != 3 || !strings.HasPrefix(splitResp[1], "SERVERHASH=") ||
|
||||
!strings.HasPrefix(splitResp[2], "SERVERNONCE=") {
|
||||
return c.protoErr("Invalid AUTHCHALLENGE response")
|
||||
}
|
||||
serverHash, err := hex.DecodeString(splitResp[1][11:])
|
||||
if err != nil {
|
||||
return c.protoErr("Failed to decode ServerHash: %v", err)
|
||||
}
|
||||
if len(serverHash) != 32 {
|
||||
return c.protoErr("Invalid ServerHash length: %d", len(serverHash))
|
||||
}
|
||||
serverNonce, err := hex.DecodeString(splitResp[2][12:])
|
||||
if err != nil {
|
||||
return c.protoErr("Failed to decode ServerNonce: %v", err)
|
||||
}
|
||||
if len(serverNonce) != 32 {
|
||||
return c.protoErr("Invalid ServerNonce length: %d", len(serverNonce))
|
||||
}
|
||||
|
||||
// Validate the ServerHash.
|
||||
m := hmac.New(sha256.New, []byte("Tor safe cookie authentication server-to-controller hash"))
|
||||
m.Write(cookie)
|
||||
m.Write(clientNonce[:])
|
||||
m.Write(serverNonce)
|
||||
dervServerHash := m.Sum(nil)
|
||||
if !hmac.Equal(serverHash, dervServerHash) {
|
||||
return c.protoErr("invalid ServerHash: mismatch")
|
||||
}
|
||||
|
||||
// Calculate the ClientHash, and issue the AUTHENTICATE.
|
||||
m = hmac.New(sha256.New, []byte("Tor safe cookie authentication controller-to-server hash"))
|
||||
m.Write(cookie)
|
||||
m.Write(clientNonce[:])
|
||||
m.Write(serverNonce)
|
||||
authBytes = m.Sum(nil)
|
||||
} else if pi.HasAuthMethod("HASHEDPASSWORD") {
|
||||
// Despite the name HASHEDPASSWORD, the raw password is actually sent. According to the code, this can either be
|
||||
// a QuotedString, or base16 encoded, so go with the later since it's easier to handle.
|
||||
if password == "" {
|
||||
return c.protoErr("password auth needs a password")
|
||||
}
|
||||
authBytes = []byte(password)
|
||||
} else {
|
||||
return c.protoErr("No supported authentication methods")
|
||||
}
|
||||
// Send it
|
||||
if err = c.sendAuthenticate(authBytes); err == nil {
|
||||
c.Authenticated = true
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Conn) sendAuthenticate(byts []byte) error {
|
||||
if len(byts) == 0 {
|
||||
return c.sendRequestIgnoreResponse("AUTHENTICATE")
|
||||
}
|
||||
return c.sendRequestIgnoreResponse("AUTHENTICATE %v", hex.EncodeToString(byts))
|
||||
}
|
38
vendor/github.com/cretz/bine/control/cmd_circuit.go
generated
vendored
Normal file
38
vendor/github.com/cretz/bine/control/cmd_circuit.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
package control
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ExtendCircuit invokes EXTENDCIRCUIT and returns the circuit ID on success.
|
||||
func (c *Conn) ExtendCircuit(circuitID string, path []string, purpose string) (string, error) {
|
||||
if circuitID == "" {
|
||||
circuitID = "0"
|
||||
}
|
||||
cmd := "EXTENDCIRCUIT " + circuitID
|
||||
if len(path) > 0 {
|
||||
cmd += " " + strings.Join(path, ",")
|
||||
}
|
||||
if purpose != "" {
|
||||
cmd += " purpose=" + purpose
|
||||
}
|
||||
resp, err := c.SendRequest(cmd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return resp.Reply[strings.LastIndexByte(resp.Reply, ' ')+1:], nil
|
||||
}
|
||||
|
||||
// SetCircuitPurpose invokes SETCIRCUITPURPOSE.
|
||||
func (c *Conn) SetCircuitPurpose(circuitID string, purpose string) error {
|
||||
return c.sendRequestIgnoreResponse("SETCIRCUITPURPOSE %v purpose=%v", circuitID, purpose)
|
||||
}
|
||||
|
||||
// CloseCircuit invokes CLOSECIRCUIT.
|
||||
func (c *Conn) CloseCircuit(circuitID string, flags []string) error {
|
||||
cmd := "CLOSECIRCUIT " + circuitID
|
||||
for _, flag := range flags {
|
||||
cmd += " " + flag
|
||||
}
|
||||
return c.sendRequestIgnoreResponse(cmd)
|
||||
}
|
65
vendor/github.com/cretz/bine/control/cmd_conf.go
generated
vendored
Normal file
65
vendor/github.com/cretz/bine/control/cmd_conf.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
package control
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/cretz/bine/torutil"
|
||||
)
|
||||
|
||||
// SetConf invokes SETCONF.
|
||||
func (c *Conn) SetConf(entries ...*KeyVal) error {
|
||||
return c.sendSetConf("SETCONF", entries)
|
||||
}
|
||||
|
||||
// ResetConf invokes RESETCONF.
|
||||
func (c *Conn) ResetConf(entries ...*KeyVal) error {
|
||||
return c.sendSetConf("RESETCONF", entries)
|
||||
}
|
||||
|
||||
func (c *Conn) sendSetConf(cmd string, entries []*KeyVal) error {
|
||||
for _, entry := range entries {
|
||||
cmd += " " + entry.Key
|
||||
if entry.ValSet() {
|
||||
cmd += "=" + torutil.EscapeSimpleQuotedStringIfNeeded(entry.Val)
|
||||
}
|
||||
}
|
||||
return c.sendRequestIgnoreResponse(cmd)
|
||||
}
|
||||
|
||||
// GetConf invokes GETCONF and returns the values for the requested keys.
|
||||
func (c *Conn) GetConf(keys ...string) ([]*KeyVal, error) {
|
||||
resp, err := c.SendRequest("GETCONF %v", strings.Join(keys, " "))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data := resp.DataWithReply()
|
||||
ret := make([]*KeyVal, 0, len(data))
|
||||
for _, data := range data {
|
||||
key, val, ok := torutil.PartitionString(data, '=')
|
||||
entry := &KeyVal{Key: key}
|
||||
if ok {
|
||||
if entry.Val, err = torutil.UnescapeSimpleQuotedStringIfNeeded(val); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(entry.Val) == 0 {
|
||||
entry.ValSetAndEmpty = true
|
||||
}
|
||||
}
|
||||
ret = append(ret, entry)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// SaveConf invokes SAVECONF.
|
||||
func (c *Conn) SaveConf(force bool) error {
|
||||
cmd := "SAVECONF"
|
||||
if force {
|
||||
cmd += " FORCE"
|
||||
}
|
||||
return c.sendRequestIgnoreResponse(cmd)
|
||||
}
|
||||
|
||||
// LoadConf invokes LOADCONF.
|
||||
func (c *Conn) LoadConf(conf string) error {
|
||||
return c.sendRequestIgnoreResponse("+LOADCONF\r\n%v\r\n.", conf)
|
||||
}
|
1218
vendor/github.com/cretz/bine/control/cmd_event.go
generated
vendored
Normal file
1218
vendor/github.com/cretz/bine/control/cmd_event.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
23
vendor/github.com/cretz/bine/control/cmd_hiddenservice.go
generated
vendored
Normal file
23
vendor/github.com/cretz/bine/control/cmd_hiddenservice.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
package control
|
||||
|
||||
// GetHiddenServiceDescriptorAsync invokes HSFETCH.
|
||||
func (c *Conn) GetHiddenServiceDescriptorAsync(address string, server string) error {
|
||||
cmd := "HSFETCH " + address
|
||||
if server != "" {
|
||||
cmd += " SERVER=" + server
|
||||
}
|
||||
return c.sendRequestIgnoreResponse(cmd)
|
||||
}
|
||||
|
||||
// PostHiddenServiceDescriptorAsync invokes HSPOST.
|
||||
func (c *Conn) PostHiddenServiceDescriptorAsync(desc string, servers []string, address string) error {
|
||||
cmd := "+HSPOST"
|
||||
for _, server := range servers {
|
||||
cmd += " SERVER=" + server
|
||||
}
|
||||
if address != "" {
|
||||
cmd += "HSADDRESS=" + address
|
||||
}
|
||||
cmd += "\r\n" + desc + "\r\n."
|
||||
return c.sendRequestIgnoreResponse(cmd)
|
||||
}
|
92
vendor/github.com/cretz/bine/control/cmd_misc.go
generated
vendored
Normal file
92
vendor/github.com/cretz/bine/control/cmd_misc.go
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
package control
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/cretz/bine/torutil"
|
||||
)
|
||||
|
||||
// Signal invokes SIGNAL.
|
||||
func (c *Conn) Signal(signal string) error {
|
||||
return c.sendRequestIgnoreResponse("SIGNAL %v", signal)
|
||||
}
|
||||
|
||||
// Quit invokes QUIT.
|
||||
func (c *Conn) Quit() error {
|
||||
return c.sendRequestIgnoreResponse("QUIT")
|
||||
}
|
||||
|
||||
// MapAddresses invokes MAPADDRESS and returns mapped addresses.
|
||||
func (c *Conn) MapAddresses(addresses ...*KeyVal) ([]*KeyVal, error) {
|
||||
cmd := "MAPADDRESS"
|
||||
for _, address := range addresses {
|
||||
cmd += " " + address.Key + "=" + address.Val
|
||||
}
|
||||
resp, err := c.SendRequest(cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data := resp.DataWithReply()
|
||||
ret := make([]*KeyVal, 0, len(data))
|
||||
for _, address := range data {
|
||||
mappedAddress := &KeyVal{}
|
||||
mappedAddress.Key, mappedAddress.Val, _ = torutil.PartitionString(address, '=')
|
||||
ret = append(ret, mappedAddress)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// GetInfo invokes GETINTO and returns values for requested keys.
|
||||
func (c *Conn) GetInfo(keys ...string) ([]*KeyVal, error) {
|
||||
resp, err := c.SendRequest("GETINFO %v", strings.Join(keys, " "))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := make([]*KeyVal, 0, len(resp.Data))
|
||||
for _, val := range resp.Data {
|
||||
infoVal := &KeyVal{}
|
||||
infoVal.Key, infoVal.Val, _ = torutil.PartitionString(val, '=')
|
||||
if infoVal.Val, err = torutil.UnescapeSimpleQuotedStringIfNeeded(infoVal.Val); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, infoVal)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// PostDescriptor invokes POSTDESCRIPTOR.
|
||||
func (c *Conn) PostDescriptor(descriptor string, purpose string, cache string) error {
|
||||
cmd := "+POSTDESCRIPTOR"
|
||||
if purpose != "" {
|
||||
cmd += " purpose=" + purpose
|
||||
}
|
||||
if cache != "" {
|
||||
cmd += " cache=" + cache
|
||||
}
|
||||
cmd += "\r\n" + descriptor + "\r\n."
|
||||
return c.sendRequestIgnoreResponse(cmd)
|
||||
}
|
||||
|
||||
// UseFeatures invokes USEFEATURE.
|
||||
func (c *Conn) UseFeatures(features ...string) error {
|
||||
return c.sendRequestIgnoreResponse("USEFEATURE " + strings.Join(features, " "))
|
||||
}
|
||||
|
||||
// ResolveAsync invokes RESOLVE.
|
||||
func (c *Conn) ResolveAsync(address string, reverse bool) error {
|
||||
cmd := "RESOLVE "
|
||||
if reverse {
|
||||
cmd += "mode=reverse "
|
||||
}
|
||||
return c.sendRequestIgnoreResponse(cmd + address)
|
||||
}
|
||||
|
||||
// TakeOwnership invokes TAKEOWNERSHIP.
|
||||
func (c *Conn) TakeOwnership() error {
|
||||
return c.sendRequestIgnoreResponse("TAKEOWNERSHIP")
|
||||
}
|
||||
|
||||
// DropGuards invokes DROPGUARDS.
|
||||
func (c *Conn) DropGuards() error {
|
||||
return c.sendRequestIgnoreResponse("DROPGUARDS")
|
||||
}
|
201
vendor/github.com/cretz/bine/control/cmd_onion.go
generated
vendored
Normal file
201
vendor/github.com/cretz/bine/control/cmd_onion.go
generated
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
package control
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cretz/bine/torutil"
|
||||
"github.com/cretz/bine/torutil/ed25519"
|
||||
)
|
||||
|
||||
// KeyType is a key type for Key in AddOnion.
|
||||
type KeyType string
|
||||
|
||||
const (
|
||||
// KeyTypeNew is NEW.
|
||||
KeyTypeNew KeyType = "NEW"
|
||||
// KeyTypeRSA1024 is RSA1024.
|
||||
KeyTypeRSA1024 KeyType = "RSA1024"
|
||||
// KeyTypeED25519V3 is ED25519-V3.
|
||||
KeyTypeED25519V3 KeyType = "ED25519-V3"
|
||||
)
|
||||
|
||||
// KeyAlgo is a key algorithm for GenKey on AddOnion.
|
||||
type KeyAlgo string
|
||||
|
||||
const (
|
||||
// KeyAlgoBest is BEST.
|
||||
KeyAlgoBest KeyAlgo = "BEST"
|
||||
// KeyAlgoRSA1024 is RSA1024.
|
||||
KeyAlgoRSA1024 KeyAlgo = "RSA1024"
|
||||
// KeyAlgoED25519V3 is ED25519-V3.
|
||||
KeyAlgoED25519V3 KeyAlgo = "ED25519-V3"
|
||||
)
|
||||
|
||||
// Key is a type of key to use for AddOnion. Implementations include GenKey,
|
||||
// RSAKey, and ED25519Key.
|
||||
type Key interface {
|
||||
// Type is the KeyType for AddOnion.
|
||||
Type() KeyType
|
||||
// Blob is the serialized key for AddOnion.
|
||||
Blob() string
|
||||
}
|
||||
|
||||
// KeyFromString creates a Key for AddOnion based on a response string.
|
||||
func KeyFromString(str string) (Key, error) {
|
||||
typ, blob, _ := torutil.PartitionString(str, ':')
|
||||
switch KeyType(typ) {
|
||||
case KeyTypeNew:
|
||||
return GenKeyFromBlob(blob), nil
|
||||
case KeyTypeRSA1024:
|
||||
return RSA1024KeyFromBlob(blob)
|
||||
case KeyTypeED25519V3:
|
||||
return ED25519KeyFromBlob(blob)
|
||||
default:
|
||||
return nil, fmt.Errorf("Unrecognized key type: %v", typ)
|
||||
}
|
||||
}
|
||||
|
||||
// GenKey is a Key for AddOnion that asks Tor to generate a key for the given
|
||||
// algorithm.
|
||||
type GenKey KeyAlgo
|
||||
|
||||
// GenKeyFromBlob creates a GenKey for the given response blob which is a
|
||||
// KeyAlgo.
|
||||
func GenKeyFromBlob(blob string) GenKey { return GenKey(KeyAlgo(blob)) }
|
||||
|
||||
// Type implements Key.Type.
|
||||
func (GenKey) Type() KeyType { return KeyTypeNew }
|
||||
|
||||
// Blob implements Key.Blob.
|
||||
func (g GenKey) Blob() string { return string(g) }
|
||||
|
||||
// RSAKey is a Key for AddOnion that is a RSA-1024 key (i.e. v2).
|
||||
type RSAKey struct{ *rsa.PrivateKey }
|
||||
|
||||
// RSA1024KeyFromBlob creates a RSAKey for the given response blob.
|
||||
func RSA1024KeyFromBlob(blob string) (*RSAKey, error) {
|
||||
byts, err := base64.StdEncoding.DecodeString(blob)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rsaKey, err := x509.ParsePKCS1PrivateKey(byts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RSAKey{rsaKey}, nil
|
||||
}
|
||||
|
||||
// Type implements Key.Type.
|
||||
func (*RSAKey) Type() KeyType { return KeyTypeRSA1024 }
|
||||
|
||||
// Blob implements Key.Blob.
|
||||
func (r *RSAKey) Blob() string {
|
||||
return base64.StdEncoding.EncodeToString(x509.MarshalPKCS1PrivateKey(r.PrivateKey))
|
||||
}
|
||||
|
||||
// ED25519Key is a Key for AddOnion that is a ed25519 key (i.e. v3).
|
||||
type ED25519Key struct{ ed25519.KeyPair }
|
||||
|
||||
// ED25519KeyFromBlob creates a ED25519Key for the given response blob.
|
||||
func ED25519KeyFromBlob(blob string) (*ED25519Key, error) {
|
||||
byts, err := base64.StdEncoding.DecodeString(blob)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ED25519Key{ed25519.PrivateKey(byts).KeyPair()}, nil
|
||||
}
|
||||
|
||||
// Type implements Key.Type.
|
||||
func (*ED25519Key) Type() KeyType { return KeyTypeED25519V3 }
|
||||
|
||||
// Blob implements Key.Blob.
|
||||
func (e *ED25519Key) Blob() string { return base64.StdEncoding.EncodeToString(e.PrivateKey()) }
|
||||
|
||||
// AddOnionRequest is a set of request params for AddOnion.
|
||||
type AddOnionRequest struct {
|
||||
// Key is the key to use or GenKey if Tor should generate it.
|
||||
Key Key
|
||||
// Flags are ADD_ONION flags.
|
||||
Flags []string
|
||||
// MaxStreams is ADD_ONION MaxStreams.
|
||||
MaxStreams int
|
||||
// Ports are ADD_ONION Port values. Key is virtual port, Val is target
|
||||
// port (or can be empty to use virtual port).
|
||||
Ports []*KeyVal
|
||||
// ClientAuths are ADD_ONION ClientAuth values. If value is empty string,
|
||||
// Tor will generate the password.
|
||||
ClientAuths map[string]string
|
||||
}
|
||||
|
||||
// AddOnionResponse is the response for AddOnion.
|
||||
type AddOnionResponse struct {
|
||||
// ServiceID is the ADD_ONION response ServiceID value.
|
||||
ServiceID string
|
||||
// Key is the ADD_ONION response PrivateKey value.
|
||||
Key Key
|
||||
// ClientAuths are the ADD_ONION response ClientAuth values.
|
||||
ClientAuths map[string]string
|
||||
// RawResponse is the raw ADD_ONION response.
|
||||
RawResponse *Response
|
||||
}
|
||||
|
||||
// AddOnion invokes ADD_ONION and returns its response.
|
||||
func (c *Conn) AddOnion(req *AddOnionRequest) (*AddOnionResponse, error) {
|
||||
// Build command
|
||||
if req.Key == nil {
|
||||
return nil, c.protoErr("Key required")
|
||||
}
|
||||
cmd := "ADD_ONION " + string(req.Key.Type()) + ":" + req.Key.Blob()
|
||||
if len(req.Flags) > 0 {
|
||||
cmd += " Flags=" + strings.Join(req.Flags, ",")
|
||||
}
|
||||
if req.MaxStreams > 0 {
|
||||
cmd += " MaxStreams=" + strconv.Itoa(req.MaxStreams)
|
||||
}
|
||||
for _, port := range req.Ports {
|
||||
cmd += " Port=" + port.Key
|
||||
if port.Val != "" {
|
||||
cmd += "," + port.Val
|
||||
}
|
||||
}
|
||||
for name, blob := range req.ClientAuths {
|
||||
cmd += " ClientAuth=" + name
|
||||
if blob != "" {
|
||||
cmd += ":" + blob
|
||||
}
|
||||
}
|
||||
// Invoke and read response
|
||||
resp, err := c.SendRequest(cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := &AddOnionResponse{RawResponse: resp}
|
||||
for _, data := range resp.Data {
|
||||
key, val, _ := torutil.PartitionString(data, '=')
|
||||
switch key {
|
||||
case "ServiceID":
|
||||
ret.ServiceID = val
|
||||
case "PrivateKey":
|
||||
if ret.Key, err = KeyFromString(val); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "ClientAuth":
|
||||
name, pass, _ := torutil.PartitionString(val, ':')
|
||||
if ret.ClientAuths == nil {
|
||||
ret.ClientAuths = map[string]string{}
|
||||
}
|
||||
ret.ClientAuths[name] = pass
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// DelOnion invokes DELONION.
|
||||
func (c *Conn) DelOnion(serviceID string) error {
|
||||
return c.sendRequestIgnoreResponse("DEL_ONION %v", serviceID)
|
||||
}
|
76
vendor/github.com/cretz/bine/control/cmd_protocolinfo.go
generated
vendored
Normal file
76
vendor/github.com/cretz/bine/control/cmd_protocolinfo.go
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
package control
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/cretz/bine/torutil"
|
||||
)
|
||||
|
||||
// ProtocolInfo is the protocol info result of Conn.ProtocolInfo.
|
||||
type ProtocolInfo struct {
|
||||
AuthMethods []string
|
||||
CookieFile string
|
||||
TorVersion string
|
||||
RawResponse *Response
|
||||
}
|
||||
|
||||
// HasAuthMethod checks if ProtocolInfo contains the requested auth method.
|
||||
func (p *ProtocolInfo) HasAuthMethod(authMethod string) bool {
|
||||
for _, m := range p.AuthMethods {
|
||||
if m == authMethod {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ProtocolInfo invokes PROTOCOLINFO on first invocation and returns a cached
|
||||
// result on all others.
|
||||
func (c *Conn) ProtocolInfo() (*ProtocolInfo, error) {
|
||||
var err error
|
||||
if c.protocolInfo == nil {
|
||||
c.protocolInfo, err = c.sendProtocolInfo()
|
||||
}
|
||||
return c.protocolInfo, err
|
||||
}
|
||||
|
||||
func (c *Conn) sendProtocolInfo() (*ProtocolInfo, error) {
|
||||
resp, err := c.SendRequest("PROTOCOLINFO")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Check data vals
|
||||
ret := &ProtocolInfo{RawResponse: resp}
|
||||
for _, piece := range resp.Data {
|
||||
key, val, ok := torutil.PartitionString(piece, ' ')
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "PROTOCOLINFO":
|
||||
if val != "1" {
|
||||
return nil, c.protoErr("Invalid PIVERSION: %v", val)
|
||||
}
|
||||
case "AUTH":
|
||||
methods, cookieFile, _ := torutil.PartitionString(val, ' ')
|
||||
if !strings.HasPrefix(methods, "METHODS=") {
|
||||
continue
|
||||
}
|
||||
if cookieFile != "" {
|
||||
if !strings.HasPrefix(cookieFile, "COOKIEFILE=") {
|
||||
continue
|
||||
}
|
||||
if ret.CookieFile, err = torutil.UnescapeSimpleQuotedString(cookieFile[11:]); err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
ret.AuthMethods = strings.Split(methods[8:], ",")
|
||||
case "VERSION":
|
||||
torVersion, _, _ := torutil.PartitionString(val, ' ')
|
||||
if strings.HasPrefix(torVersion, "Tor=") {
|
||||
ret.TorVersion, err = torutil.UnescapeSimpleQuotedString(torVersion[4:])
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
31
vendor/github.com/cretz/bine/control/cmd_stream.go
generated
vendored
Normal file
31
vendor/github.com/cretz/bine/control/cmd_stream.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
package control
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// AttachStream invokes ATTACHSTREAM.
|
||||
func (c *Conn) AttachStream(streamID string, circuitID string, hopNum int) error {
|
||||
if circuitID == "" {
|
||||
circuitID = "0"
|
||||
}
|
||||
cmd := "ATTACHSTREAM " + streamID + " " + circuitID
|
||||
if hopNum > 0 {
|
||||
cmd += " HOP=" + strconv.Itoa(hopNum)
|
||||
}
|
||||
return c.sendRequestIgnoreResponse(cmd)
|
||||
}
|
||||
|
||||
// RedirectStream invokes REDIRECTSTREAM.
|
||||
func (c *Conn) RedirectStream(streamID string, address string, port int) error {
|
||||
cmd := "REDIRECTSTREAM " + streamID + " " + address
|
||||
if port > 0 {
|
||||
cmd += " " + strconv.Itoa(port)
|
||||
}
|
||||
return c.sendRequestIgnoreResponse(cmd)
|
||||
}
|
||||
|
||||
// CloseStream invokes CLOSESTREAM.
|
||||
func (c *Conn) CloseStream(streamID string, reason string) error {
|
||||
return c.sendRequestIgnoreResponse("CLOSESTREAM %v %v", streamID, reason)
|
||||
}
|
102
vendor/github.com/cretz/bine/control/conn.go
generated
vendored
Normal file
102
vendor/github.com/cretz/bine/control/conn.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
package control
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/textproto"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Conn is the connection to the Tor control port.
|
||||
type Conn struct {
|
||||
// DebugWriter is the writer that debug logs for this library (not Tor
|
||||
// itself) will be written to. If nil, no debug logs are generated/written.
|
||||
DebugWriter io.Writer
|
||||
|
||||
// This is the underlying connection.
|
||||
conn *textproto.Conn
|
||||
|
||||
// This is set lazily by ProtocolInfo().
|
||||
protocolInfo *ProtocolInfo
|
||||
|
||||
// True if Authenticate has been called successfully.
|
||||
Authenticated bool
|
||||
|
||||
// The lock fot eventListeners
|
||||
eventListenersLock sync.RWMutex
|
||||
// The value slices can be traversed outside of lock, they are completely
|
||||
// replaced on change, never mutated. But the map itself must be locked on
|
||||
// when reading or writing.
|
||||
eventListeners map[EventCode][]chan<- Event
|
||||
|
||||
// This mutex is locked on when an entire response needs to be read. It
|
||||
// helps synchronize accesses to the response by the asynchronous response
|
||||
// listeners and the synchronous responses.
|
||||
readLock sync.Mutex
|
||||
}
|
||||
|
||||
// NewConn creates a Conn from the given textproto connection.
|
||||
func NewConn(conn *textproto.Conn) *Conn {
|
||||
return &Conn{
|
||||
conn: conn,
|
||||
eventListeners: map[EventCode][]chan<- Event{},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) sendRequestIgnoreResponse(format string, args ...interface{}) error {
|
||||
_, err := c.SendRequest(format, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
// SendRequest sends a synchronous request to Tor and awaits the response. If
|
||||
// the response errors, the error result will be set, but the response will be
|
||||
// set also. This is usually not directly used by callers, but instead called by
|
||||
// higher-level methods.
|
||||
func (c *Conn) SendRequest(format string, args ...interface{}) (*Response, error) {
|
||||
if c.debugEnabled() {
|
||||
c.debugf("Write line: %v", fmt.Sprintf(format, args...))
|
||||
}
|
||||
id, err := c.conn.Cmd(format, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.readLock.Lock()
|
||||
defer c.readLock.Unlock()
|
||||
c.conn.StartResponse(id)
|
||||
defer c.conn.EndResponse(id)
|
||||
// Get the first non-async response
|
||||
var resp *Response
|
||||
for {
|
||||
if resp, err = c.ReadResponse(); err != nil || !resp.IsAsync() {
|
||||
break
|
||||
}
|
||||
c.relayAsyncEvents(resp)
|
||||
}
|
||||
if err == nil && !resp.IsOk() {
|
||||
err = resp.Err
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// Close sends a QUIT and closes the underlying Tor connection. This does not
|
||||
// error if the QUIT is not accepted but does relay any error that occurs while
|
||||
// closing the underlying connection.
|
||||
func (c *Conn) Close() error {
|
||||
// Ignore the response and ignore the error
|
||||
c.Quit()
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
func (c *Conn) debugEnabled() bool {
|
||||
return c.DebugWriter != nil
|
||||
}
|
||||
|
||||
func (c *Conn) debugf(format string, args ...interface{}) {
|
||||
if w := c.DebugWriter; w != nil {
|
||||
fmt.Fprintf(w, format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (*Conn) protoErr(format string, args ...interface{}) textproto.ProtocolError {
|
||||
return textproto.ProtocolError(fmt.Sprintf(format, args...))
|
||||
}
|
10
vendor/github.com/cretz/bine/control/doc.go
generated
vendored
Normal file
10
vendor/github.com/cretz/bine/control/doc.go
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
// Package control implements a low-level client for the Tor control spec
|
||||
// version 1.
|
||||
//
|
||||
// The primary entrypoint is the Conn struct, instantiated with NewConn. This is
|
||||
// the low-level layer to the control port of an already-running Tor instance.
|
||||
// Most developers will prefer the tor package adjacent to this one for a higher
|
||||
// level abstraction over the process and this connection.
|
||||
//
|
||||
// Some of this code is lifted from https://github.com/yawning/bulb with thanks.
|
||||
package control
|
40
vendor/github.com/cretz/bine/control/keyval.go
generated
vendored
Normal file
40
vendor/github.com/cretz/bine/control/keyval.go
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
package control
|
||||
|
||||
// KeyVal is a simple key-value struct. In cases where Val can be nil, an empty
|
||||
// string represents that unless ValSetAndEmpty is true.
|
||||
type KeyVal struct {
|
||||
// Key is the always-present key
|
||||
Key string
|
||||
|
||||
// Val is the value. If it's an empty string and nils are accepted/supported
|
||||
// where this is used, it means nil unless ValSetAndEmpty is true.
|
||||
Val string
|
||||
|
||||
// ValSetAndEmpty is true when Val is an empty string, the associated
|
||||
// command supports nils, and Val should NOT be treated as nil. False
|
||||
// otherwise.
|
||||
ValSetAndEmpty bool
|
||||
}
|
||||
|
||||
// NewKeyVal creates a new key-value pair.
|
||||
func NewKeyVal(key string, val string) *KeyVal {
|
||||
return &KeyVal{Key: key, Val: val}
|
||||
}
|
||||
|
||||
// KeyVals creates multiple new key-value pairs from the given strings. The
|
||||
// provided set of strings must have a length that is a multiple of 2.
|
||||
func KeyVals(keysAndVals ...string) []*KeyVal {
|
||||
if len(keysAndVals)%2 != 0 {
|
||||
panic("Expected multiple of 2")
|
||||
}
|
||||
ret := make([]*KeyVal, len(keysAndVals)/2)
|
||||
for i := 0; i < len(ret); i++ {
|
||||
ret[i] = NewKeyVal(keysAndVals[i*2], keysAndVals[i*2+1])
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// ValSet returns true if Val is either non empty or ValSetAndEmpty is true.
|
||||
func (k *KeyVal) ValSet() bool {
|
||||
return len(k.Val) > 0 || k.ValSetAndEmpty
|
||||
}
|
106
vendor/github.com/cretz/bine/control/response.go
generated
vendored
Normal file
106
vendor/github.com/cretz/bine/control/response.go
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
package control
|
||||
|
||||
import (
|
||||
"net/textproto"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Response is a response to a control port command or an asynchronous event.
|
||||
type Response struct {
|
||||
// Err is the status code and string representation associated with a
|
||||
// response. Responses that have completed successfully will also have Err
|
||||
// set to indicate such.
|
||||
Err *textproto.Error
|
||||
|
||||
// Reply is the text on the EndReplyLine of the response.
|
||||
Reply string
|
||||
|
||||
// Data is the MidReplyLines/DataReplyLines of the response. Dot encoded
|
||||
// data is "decoded" and presented as a single string (terminal ".CRLF"
|
||||
// removed, all intervening CRs stripped).
|
||||
Data []string
|
||||
|
||||
// RawLines is all of the lines of a response, without CRLFs.
|
||||
RawLines []string
|
||||
}
|
||||
|
||||
// IsOk returns true if the response status code indicates success or an
|
||||
// asynchronous event.
|
||||
func (r *Response) IsOk() bool {
|
||||
switch r.Err.Code {
|
||||
case StatusOk, StatusOkUnnecessary, StatusAsyncEvent:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// DataWithReply returns a combination of Data and Reply to give a full set of
|
||||
// the lines of the response.
|
||||
func (r *Response) DataWithReply() []string {
|
||||
ret := make([]string, len(r.Data)+1)
|
||||
copy(ret, r.Data)
|
||||
ret[len(ret)-1] = r.Reply
|
||||
return ret
|
||||
}
|
||||
|
||||
// IsAsync returns true if the response is an asynchronous event.
|
||||
func (r *Response) IsAsync() bool {
|
||||
return r.Err.Code == StatusAsyncEvent
|
||||
}
|
||||
|
||||
// ReadResponse returns the next response object.
|
||||
func (c *Conn) ReadResponse() (*Response, error) {
|
||||
var resp *Response
|
||||
var statusCode int
|
||||
for {
|
||||
line, err := c.conn.ReadLine()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.debugf("Read line: %v", line)
|
||||
|
||||
// Parse the line that was just read.
|
||||
if len(line) < 4 {
|
||||
return nil, c.protoErr("Truncated response: %v", line)
|
||||
}
|
||||
if code, err := strconv.Atoi(line[0:3]); err != nil || code < 100 {
|
||||
return nil, c.protoErr("Invalid status code: %v", line[0:3])
|
||||
} else if resp == nil {
|
||||
resp = &Response{}
|
||||
statusCode = code
|
||||
} else if code != statusCode {
|
||||
// The status code should stay fixed for all lines of the response, since events can't be interleaved with
|
||||
// response lines.
|
||||
return nil, c.protoErr("Status code changed: %v != %v", code, statusCode)
|
||||
}
|
||||
resp.RawLines = append(resp.RawLines, line)
|
||||
switch line[3] {
|
||||
case ' ':
|
||||
// Final line in the response.
|
||||
resp.Reply = line[4:]
|
||||
resp.Err = statusCodeToError(statusCode, resp.Reply)
|
||||
return resp, nil
|
||||
case '-':
|
||||
// Continuation, keep reading.
|
||||
resp.Data = append(resp.Data, line[4:])
|
||||
case '+':
|
||||
// A "dot-encoded" payload follows.
|
||||
dotBody, err := c.conn.ReadDotBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dotBodyStr := strings.TrimRight(string(dotBody), "\n\r")
|
||||
// c.debugf("Read dot body:\n---\n%v\n---", dotBodyStr)
|
||||
resp.Data = append(resp.Data, line[4:]+"\r\n"+dotBodyStr)
|
||||
dotLines := strings.Split(dotBodyStr, "\n")
|
||||
for _, dotLine := range dotLines[:len(dotLines)-1] {
|
||||
resp.RawLines = append(resp.RawLines, dotLine)
|
||||
}
|
||||
resp.RawLines = append(resp.RawLines, ".")
|
||||
default:
|
||||
return nil, c.protoErr("Invalid separator: '%v'", line[3])
|
||||
}
|
||||
}
|
||||
}
|
64
vendor/github.com/cretz/bine/control/status.go
generated
vendored
Normal file
64
vendor/github.com/cretz/bine/control/status.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
package control
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/textproto"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// The various control port StatusCode constants.
|
||||
const (
|
||||
StatusOk = 250
|
||||
StatusOkUnnecessary = 251
|
||||
|
||||
StatusErrResourceExhausted = 451
|
||||
StatusErrSyntaxError = 500
|
||||
StatusErrUnrecognizedCmd = 510
|
||||
StatusErrUnimplementedCmd = 511
|
||||
StatusErrSyntaxErrorArg = 512
|
||||
StatusErrUnrecognizedCmdArg = 513
|
||||
StatusErrAuthenticationRequired = 514
|
||||
StatusErrBadAuthentication = 515
|
||||
StatusErrUnspecifiedTorError = 550
|
||||
StatusErrInternalError = 551
|
||||
StatusErrUnrecognizedEntity = 552
|
||||
StatusErrInvalidConfigValue = 553
|
||||
StatusErrInvalidDescriptor = 554
|
||||
StatusErrUnmanagedEntity = 555
|
||||
|
||||
StatusAsyncEvent = 650
|
||||
)
|
||||
|
||||
var statusCodeStringMap = map[int]string{
|
||||
StatusOk: "OK",
|
||||
StatusOkUnnecessary: "Operation was unnecessary",
|
||||
|
||||
StatusErrResourceExhausted: "Resource exhausted",
|
||||
StatusErrSyntaxError: "Syntax error: protocol",
|
||||
StatusErrUnrecognizedCmd: "Unrecognized command",
|
||||
StatusErrUnimplementedCmd: "Unimplemented command",
|
||||
StatusErrSyntaxErrorArg: "Syntax error in command argument",
|
||||
StatusErrUnrecognizedCmdArg: "Unrecognized command argument",
|
||||
StatusErrAuthenticationRequired: "Authentication required",
|
||||
StatusErrBadAuthentication: "Bad authentication",
|
||||
StatusErrUnspecifiedTorError: "Unspecified Tor error",
|
||||
StatusErrInternalError: "Internal error",
|
||||
StatusErrUnrecognizedEntity: "Unrecognized entity",
|
||||
StatusErrInvalidConfigValue: "Invalid configuration value",
|
||||
StatusErrInvalidDescriptor: "Invalid descriptor",
|
||||
StatusErrUnmanagedEntity: "Unmanaged entity",
|
||||
|
||||
StatusAsyncEvent: "Asynchronous event notification",
|
||||
}
|
||||
|
||||
func statusCodeToError(code int, reply string) *textproto.Error {
|
||||
err := new(textproto.Error)
|
||||
err.Code = code
|
||||
if msg, ok := statusCodeStringMap[code]; ok {
|
||||
trimmedReply := strings.TrimSpace(strings.TrimPrefix(reply, msg))
|
||||
err.Msg = fmt.Sprintf("%s: %s", msg, trimmedReply)
|
||||
} else {
|
||||
err.Msg = fmt.Sprintf("Unknown status code (%03d): %s", code, reply)
|
||||
}
|
||||
return err
|
||||
}
|
82
vendor/github.com/cretz/bine/process/process.go
generated
vendored
Normal file
82
vendor/github.com/cretz/bine/process/process.go
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
// Package process is the low-level abstraction for a Tor instance.
|
||||
//
|
||||
// The standard use is to create a Creator with NewCreator and the path to the
|
||||
// Tor executable. The child package 'embedded' can be used if Tor is statically
|
||||
// linked in the binary. Most developers will prefer the tor package adjacent to
|
||||
// this one for a higher level abstraction over the process and control port
|
||||
// connection.
|
||||
package process
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cretz/bine/torutil"
|
||||
)
|
||||
|
||||
// Process is the interface implemented by Tor processes.
|
||||
type Process interface {
|
||||
// Start starts the Tor process in the background and returns. It is
|
||||
// analagous to os/exec.Cmd.Start.
|
||||
Start() error
|
||||
// Wait waits for the Tor process to exit and returns error if it was not a
|
||||
// successful exit. It is analagous to os/exec.Cmd.Wait.
|
||||
Wait() error
|
||||
// ControlConn is used for statically linked, embedded processes to create
|
||||
// a controller connection. For non-embedded processes or Tor versions that
|
||||
// don't support embedded control connections, ErrControlConnUnsupported is
|
||||
// returned. Note, this should only be called once per process before
|
||||
// Start, and the connection does not need to be closed.
|
||||
EmbeddedControlConn() (net.Conn, error)
|
||||
}
|
||||
|
||||
// Creator is the interface for process creation.
|
||||
type Creator interface {
|
||||
New(ctx context.Context, args ...string) (Process, error)
|
||||
}
|
||||
|
||||
type CmdCreatorFunc func(ctx context.Context, args ...string) (*exec.Cmd, error)
|
||||
|
||||
// NewCreator creates a Creator for external Tor process execution based on the
|
||||
// given exe path.
|
||||
func NewCreator(exePath string) Creator {
|
||||
return CmdCreatorFunc(func(ctx context.Context, args ...string) (*exec.Cmd, error) {
|
||||
cmd := exec.CommandContext(ctx, exePath, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd, nil
|
||||
})
|
||||
}
|
||||
|
||||
type exeProcess struct {
|
||||
*exec.Cmd
|
||||
}
|
||||
|
||||
func (c CmdCreatorFunc) New(ctx context.Context, args ...string) (Process, error) {
|
||||
cmd, err := c(ctx, args...)
|
||||
return &exeProcess{cmd}, err
|
||||
}
|
||||
|
||||
// ErrControlConnUnsupported is returned by Process.EmbeddedControlConn when
|
||||
// it is unsupported.
|
||||
var ErrControlConnUnsupported = fmt.Errorf("Control conn not supported")
|
||||
|
||||
func (e *exeProcess) EmbeddedControlConn() (net.Conn, error) {
|
||||
return nil, ErrControlConnUnsupported
|
||||
}
|
||||
|
||||
// ControlPortFromFileContents reads a control port file that is written by Tor
|
||||
// when ControlPortWriteToFile is set.
|
||||
func ControlPortFromFileContents(contents string) (int, error) {
|
||||
contents = strings.TrimSpace(contents)
|
||||
_, port, ok := torutil.PartitionString(contents, ':')
|
||||
if !ok || !strings.HasPrefix(contents, "PORT=") {
|
||||
return 0, fmt.Errorf("Invalid port format: %v", contents)
|
||||
}
|
||||
return strconv.Atoi(port)
|
||||
}
|
111
vendor/github.com/cretz/bine/tor/dialer.go
generated
vendored
Normal file
111
vendor/github.com/cretz/bine/tor/dialer.go
generated
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
package tor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
|
||||
// Dialer is a wrapper around a proxy.Dialer for dialing connections.
|
||||
type Dialer struct {
|
||||
proxy.Dialer
|
||||
}
|
||||
|
||||
// DialConf is the configuration used for Dialer.
|
||||
type DialConf struct {
|
||||
// ProxyAddress is the address for the SOCKS5 proxy. If empty, it is looked
|
||||
// up.
|
||||
ProxyAddress string
|
||||
|
||||
// ProxyNetwork is the network for the SOCKS5 proxy. If ProxyAddress is
|
||||
// empty, this value is ignored and overridden by what is looked up. If this
|
||||
// is empty and ProxyAddress is not empty, it defaults to "tcp".
|
||||
ProxyNetwork string
|
||||
|
||||
// ProxyAuth is the auth for the proxy. Since Tor's SOCKS5 proxy is
|
||||
// unauthenticated, this is rarely needed. It can be used when
|
||||
// IsolateSOCKSAuth is set to ensure separate circuits.
|
||||
//
|
||||
// This should not be confused with downstream SOCKS proxy authentication
|
||||
// which is set via Tor values for Socks5ProxyUsername and
|
||||
// Socks5ProxyPassword when Socks5Proxy is set.
|
||||
ProxyAuth *proxy.Auth
|
||||
|
||||
// SkipEnableNetwork, if true, will skip the enable network step in Dialer.
|
||||
SkipEnableNetwork bool
|
||||
|
||||
// Forward is the dialer to forward to. If nil, just uses normal net dialer.
|
||||
Forward proxy.Dialer
|
||||
}
|
||||
|
||||
// Dialer creates a new Dialer for the given configuration. Context can be nil.
|
||||
// If conf is nil, a default is used.
|
||||
func (t *Tor) Dialer(ctx context.Context, conf *DialConf) (*Dialer, error) {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
if conf == nil {
|
||||
conf = &DialConf{}
|
||||
}
|
||||
// Enable the network if requested
|
||||
if !conf.SkipEnableNetwork {
|
||||
if err := t.EnableNetwork(ctx, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Lookup proxy address as needed
|
||||
proxyNetwork := conf.ProxyNetwork
|
||||
proxyAddress := conf.ProxyAddress
|
||||
if proxyAddress == "" {
|
||||
info, err := t.Control.GetInfo("net/listeners/socks")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(info) != 1 || info[0].Key != "net/listeners/socks" {
|
||||
return nil, fmt.Errorf("Unable to get socks proxy address")
|
||||
}
|
||||
proxyAddress = info[0].Val
|
||||
if strings.HasPrefix(proxyAddress, "unix:") {
|
||||
proxyAddress = proxyAddress[5:]
|
||||
proxyNetwork = "unix"
|
||||
} else {
|
||||
proxyNetwork = "tcp"
|
||||
}
|
||||
} else if proxyNetwork == "" {
|
||||
proxyNetwork = "tcp"
|
||||
}
|
||||
|
||||
dialer, err := proxy.SOCKS5(proxyNetwork, proxyAddress, conf.ProxyAuth, conf.Forward)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Dialer{dialer}, nil
|
||||
}
|
||||
|
||||
// DialContext is the equivalent of net.DialContext.
|
||||
//
|
||||
// TODO: Remove when https://github.com/golang/go/issues/17759 is released.
|
||||
func (d *Dialer) DialContext(ctx context.Context, network string, addr string) (net.Conn, error) {
|
||||
errCh := make(chan error, 1)
|
||||
connCh := make(chan net.Conn, 1)
|
||||
go func() {
|
||||
if conn, err := d.Dial(network, addr); err != nil {
|
||||
errCh <- err
|
||||
} else if ctx.Err() != nil {
|
||||
conn.Close()
|
||||
} else {
|
||||
connCh <- conn
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case err := <-errCh:
|
||||
return nil, err
|
||||
case conn := <-connCh:
|
||||
return conn, nil
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
7
vendor/github.com/cretz/bine/tor/doc.go
generated
vendored
Normal file
7
vendor/github.com/cretz/bine/tor/doc.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
// Package tor is the high-level client for Tor.
|
||||
//
|
||||
// The Tor type is a combination of a Tor instance and a connection to it.
|
||||
// Use Start to create Tor. Then Dialer or Listener can be used.
|
||||
//
|
||||
// Some of this code is lifted from https://github.com/yawning/bulb with thanks.
|
||||
package tor
|
343
vendor/github.com/cretz/bine/tor/listen.go
generated
vendored
Normal file
343
vendor/github.com/cretz/bine/tor/listen.go
generated
vendored
Normal file
@ -0,0 +1,343 @@
|
||||
package tor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/rsa"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/cretz/bine/control"
|
||||
"github.com/cretz/bine/torutil/ed25519"
|
||||
othered25519 "golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
// OnionService implements net.Listener and net.Addr for an onion service.
|
||||
type OnionService struct {
|
||||
// ID is the service ID for this onion service.
|
||||
ID string
|
||||
|
||||
// Key is the private key for this service. It is either the set key, the
|
||||
// generated key, or nil if asked to discard the key. If present, it is
|
||||
// *crypto/rsa.PrivateKey (1024 bit) when Version3 is false or
|
||||
// github.com/cretz/bine/torutil/ed25519.KeyPair when Version3 is true.
|
||||
Key crypto.PrivateKey
|
||||
|
||||
// Version3 says whether or not this service is a V3 service.
|
||||
Version3 bool
|
||||
|
||||
// ClientAuths is the credential set for clients. The keys are username and
|
||||
// the values are credentials. The credentials will always be present even
|
||||
// if Tor had to generate them.
|
||||
ClientAuths map[string]string
|
||||
|
||||
// LocalListener is the local TCP listener. This is always present.
|
||||
LocalListener net.Listener
|
||||
|
||||
// RemotePorts is the set of remote ports that are forwarded to the local
|
||||
// listener. This will always have at least one value.
|
||||
RemotePorts []int
|
||||
|
||||
// CloseLocalListenerOnClose is true if the local listener should be closed
|
||||
// on Close. This is set to true if a listener was created by Listen and set
|
||||
// to false of an existing LocalListener was provided to Listen.
|
||||
CloseLocalListenerOnClose bool
|
||||
|
||||
// The Tor object that created this. Needed for Close.
|
||||
Tor *Tor
|
||||
}
|
||||
|
||||
// ListenConf is the configuration for Listen calls.
|
||||
type ListenConf struct {
|
||||
// LocalPort is the local port to create a TCP listener on. If the port is
|
||||
// 0, it is automatically chosen. This is ignored if LocalListener is set.
|
||||
LocalPort int
|
||||
|
||||
// LocalListener is the specific local listener to back the onion service.
|
||||
// If this is nil (the default), then a listener is created with LocalPort.
|
||||
LocalListener net.Listener
|
||||
|
||||
// RemotePorts are the remote ports to serve the onion service on. If empty,
|
||||
// it is the same as the local port or local listener. This must have at
|
||||
// least one value if the local listener is not a *net.TCPListener.
|
||||
RemotePorts []int
|
||||
|
||||
// Key is the private key to use. If not present, a key is generated based
|
||||
// on whether Version3 is true or false. If present, it must be a
|
||||
// *crypto/rsa.PrivateKey (1024 bit), a
|
||||
// github.com/cretz/bine/torutil/ed25519.KeyPair, a
|
||||
// golang.org/x/crypto/ed25519.PrivateKey, or a
|
||||
// github.com/cretz/bine/control.Key.
|
||||
Key crypto.PrivateKey
|
||||
|
||||
// Version3 determines whether, when Key is nil, a version 2 or version 3
|
||||
// service/key will be generated. If true it is version 3 (an ed25519 key
|
||||
// and v3 onion service) and if false it is version 2 (a RSA-1024 key and v2
|
||||
// onion service). If Key is not nil, this value is ignored.
|
||||
Version3 bool
|
||||
|
||||
// ClientAuths is the set of usernames and credentials for client
|
||||
// authentication. The keys are usernames and the values are credentials. If
|
||||
// a username is present but the credential is empty, a credential is
|
||||
// generated by Tor for that user. If this is empty there is no
|
||||
// authentication.
|
||||
ClientAuths map[string]string
|
||||
|
||||
// MaxStreams is the maximum number of streams the service will accept. 0
|
||||
// means unlimited.
|
||||
MaxStreams int
|
||||
|
||||
// DiscardKey, if true and Key is nil (meaning a private key is generated),
|
||||
// tells Tor not to return the generated private key. This value is ignored
|
||||
// if Key is not nil.
|
||||
DiscardKey bool
|
||||
|
||||
// Detach, if true, prevents the default behavior of the onion service being
|
||||
// deleted when this controller connection is closed.
|
||||
Detach bool
|
||||
|
||||
// NonAnonymous must be true if Tor options HiddenServiceSingleHopMode and
|
||||
// HiddenServiceNonAnonymousMode are set. Otherwise, it must be false.
|
||||
NonAnonymous bool
|
||||
|
||||
// MaxStreamsCloseCircuit determines whether to close the circuit when the
|
||||
// maximum number of streams is exceeded. If true, the circuit is closed. If
|
||||
// false, the stream is simply not connected but the circuit stays open.
|
||||
MaxStreamsCloseCircuit bool
|
||||
|
||||
// NoWait if true will not wait until the onion service is published. If
|
||||
// false, the network will be enabled if it's not and then we will wait
|
||||
// until the onion service is published.
|
||||
NoWait bool
|
||||
}
|
||||
|
||||
// Listen creates an onion service and local listener. The context can be nil.
|
||||
// If conf is nil, the default struct value is used. Note, if this errors, any
|
||||
// listeners created here are closed but if a LocalListener is provided it may remain open.
|
||||
func (t *Tor) Listen(ctx context.Context, conf *ListenConf) (*OnionService, error) {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
// Create the service up here and make sure we close it no matter the error within
|
||||
svc := &OnionService{Tor: t, CloseLocalListenerOnClose: conf.LocalListener == nil}
|
||||
var err error
|
||||
|
||||
// Create the local listener if necessary
|
||||
svc.LocalListener = conf.LocalListener
|
||||
if svc.LocalListener == nil {
|
||||
if svc.LocalListener, err = net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(conf.LocalPort)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Henceforth, any error requires we close the svc
|
||||
|
||||
// Build the onion request
|
||||
req := &control.AddOnionRequest{MaxStreams: conf.MaxStreams, ClientAuths: conf.ClientAuths}
|
||||
// Set flags
|
||||
if conf.DiscardKey {
|
||||
req.Flags = append(req.Flags, "DiscardPK")
|
||||
}
|
||||
if conf.Detach {
|
||||
req.Flags = append(req.Flags, "Detach")
|
||||
}
|
||||
if len(conf.ClientAuths) > 0 {
|
||||
req.Flags = append(req.Flags, "BasicAuth")
|
||||
}
|
||||
if conf.NonAnonymous {
|
||||
req.Flags = append(req.Flags, "NonAnonymous")
|
||||
}
|
||||
if conf.MaxStreamsCloseCircuit {
|
||||
req.Flags = append(req.Flags, "MaxStreamsCloseCircuit")
|
||||
}
|
||||
// Set the key
|
||||
switch key := conf.Key.(type) {
|
||||
case nil:
|
||||
svc.Version3 = conf.Version3
|
||||
if conf.Version3 {
|
||||
req.Key = control.GenKey(control.KeyAlgoED25519V3)
|
||||
} else {
|
||||
req.Key = control.GenKey(control.KeyAlgoRSA1024)
|
||||
}
|
||||
case control.GenKey:
|
||||
svc.Version3 = conf.Version3
|
||||
req.Key = key
|
||||
case *rsa.PrivateKey:
|
||||
svc.Key = key
|
||||
svc.Version3 = false
|
||||
if key.N == nil || key.N.BitLen() != 1024 {
|
||||
err = fmt.Errorf("RSA key must be 1024 bits")
|
||||
} else {
|
||||
req.Key = &control.RSAKey{PrivateKey: key}
|
||||
}
|
||||
case *control.RSAKey:
|
||||
svc.Key = key.PrivateKey
|
||||
svc.Version3 = false
|
||||
if key.N == nil || key.N.BitLen() != 1024 {
|
||||
err = fmt.Errorf("RSA key must be 1024 bits")
|
||||
} else {
|
||||
req.Key = key
|
||||
}
|
||||
case ed25519.KeyPair:
|
||||
svc.Key = key
|
||||
svc.Version3 = true
|
||||
req.Key = &control.ED25519Key{key}
|
||||
case othered25519.PrivateKey:
|
||||
properKey := ed25519.FromCryptoPrivateKey(key)
|
||||
svc.Key = properKey
|
||||
svc.Version3 = true
|
||||
req.Key = &control.ED25519Key{properKey}
|
||||
case *control.ED25519Key:
|
||||
svc.Key = key.KeyPair
|
||||
svc.Version3 = true
|
||||
req.Key = key
|
||||
default:
|
||||
err = fmt.Errorf("Unrecognized key type: %T", key)
|
||||
}
|
||||
|
||||
// Apply the remote ports
|
||||
if err == nil {
|
||||
if len(conf.RemotePorts) == 0 {
|
||||
tcpAddr, ok := svc.LocalListener.Addr().(*net.TCPAddr)
|
||||
if !ok {
|
||||
err = fmt.Errorf("Unable to derive local TCP port")
|
||||
} else {
|
||||
svc.RemotePorts = []int{tcpAddr.Port}
|
||||
}
|
||||
} else {
|
||||
svc.RemotePorts = make([]int, len(conf.RemotePorts))
|
||||
copy(svc.RemotePorts, conf.RemotePorts)
|
||||
}
|
||||
}
|
||||
// Apply the local ports with the remote ports
|
||||
if err == nil {
|
||||
localAddr := svc.LocalListener.Addr().String()
|
||||
if _, ok := svc.LocalListener.(*net.UnixListener); ok {
|
||||
localAddr = "unix:" + localAddr
|
||||
}
|
||||
for _, remotePort := range svc.RemotePorts {
|
||||
req.Ports = append(req.Ports, &control.KeyVal{Key: strconv.Itoa(remotePort), Val: localAddr})
|
||||
}
|
||||
}
|
||||
|
||||
// Create the onion service
|
||||
var resp *control.AddOnionResponse
|
||||
if err == nil {
|
||||
resp, err = t.Control.AddOnion(req)
|
||||
}
|
||||
|
||||
// Apply the response to the service
|
||||
if err == nil {
|
||||
svc.ID = resp.ServiceID
|
||||
switch key := resp.Key.(type) {
|
||||
case nil:
|
||||
// Do nothing
|
||||
case *control.RSAKey:
|
||||
svc.Key = key.PrivateKey
|
||||
case *control.ED25519Key:
|
||||
svc.Key = key.KeyPair
|
||||
default:
|
||||
err = fmt.Errorf("Unrecognized result key type: %T", key)
|
||||
}
|
||||
// Client auths are the conf and then overridden by results
|
||||
if len(conf.ClientAuths) > 0 {
|
||||
svc.ClientAuths = make(map[string]string, len(conf.ClientAuths))
|
||||
for k, v := range conf.ClientAuths {
|
||||
svc.ClientAuths[k] = v
|
||||
}
|
||||
for k, v := range resp.ClientAuths {
|
||||
svc.ClientAuths[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait if necessary
|
||||
if err == nil && !conf.NoWait {
|
||||
t.Debugf("Enabling network before waiting for publication")
|
||||
// First make sure network is enabled
|
||||
if err = t.EnableNetwork(ctx, true); err == nil {
|
||||
t.Debugf("Waiting for publication")
|
||||
// Now we'll take a similar approach to Stem. Several UPLOADs are sent out, so we count em. If we see
|
||||
// UPLOADED, we succeeded. If we see failed, we count those. If there are as many failures as uploads, they
|
||||
// all failed and it's a failure. NOTE: unlike Stem's comments that say they don't, we are actually seeing
|
||||
// the service IDs for UPLOADED so we don't keep a map.
|
||||
uploadsAttempted := 0
|
||||
failures := []string{}
|
||||
_, err = t.Control.EventWait(ctx, []control.EventCode{control.EventCodeHSDesc},
|
||||
func(evt control.Event) (bool, error) {
|
||||
hs, _ := evt.(*control.HSDescEvent)
|
||||
if hs != nil && hs.Address == svc.ID {
|
||||
switch hs.Action {
|
||||
case "UPLOAD":
|
||||
uploadsAttempted++
|
||||
case "FAILED":
|
||||
failures = append(failures,
|
||||
fmt.Sprintf("Failed uploading to dir %v - reason: %v", hs.HSDir, hs.Reason))
|
||||
if len(failures) == uploadsAttempted {
|
||||
return false, fmt.Errorf("Failed all uploads, reasons: %v", failures)
|
||||
}
|
||||
case "UPLOADED":
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Give back err and close if there is an err
|
||||
if err != nil {
|
||||
if closeErr := svc.Close(); closeErr != nil {
|
||||
err = fmt.Errorf("Error on listen: %v (also got error trying to close: %v)", err, closeErr)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return svc, nil
|
||||
}
|
||||
|
||||
// Accept implements net.Listener.Accept.
|
||||
func (o *OnionService) Accept() (net.Conn, error) {
|
||||
return o.LocalListener.Accept()
|
||||
}
|
||||
|
||||
// Addr implements net.Listener.Addr just returning this object.
|
||||
func (o *OnionService) Addr() net.Addr {
|
||||
return o
|
||||
}
|
||||
|
||||
// Network implements net.Addr.Network always returning "tcp".
|
||||
func (o *OnionService) Network() string {
|
||||
return "tcp"
|
||||
}
|
||||
|
||||
// String implements net.Addr.String and returns "<serviceID>.onion:<virtport>".
|
||||
func (o *OnionService) String() string {
|
||||
return fmt.Sprintf("%v.onion:%v", o.ID, o.RemotePorts[0])
|
||||
}
|
||||
|
||||
// Close implements net.Listener.Close and deletes the onion service and closes
|
||||
// the LocalListener if CloseLocalListenerOnClose is true.
|
||||
func (o *OnionService) Close() (err error) {
|
||||
o.Tor.Debugf("Closing onion %v", o)
|
||||
// Delete the onion first
|
||||
if o.ID != "" {
|
||||
err = o.Tor.Control.DelOnion(o.ID)
|
||||
o.ID = ""
|
||||
}
|
||||
// Now if the local one needs to be closed, do it
|
||||
if o.CloseLocalListenerOnClose && o.LocalListener != nil {
|
||||
if closeErr := o.LocalListener.Close(); closeErr != nil {
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Unable to close onion: %v (also unable to close local listener: %v)", err, closeErr)
|
||||
} else {
|
||||
err = closeErr
|
||||
}
|
||||
}
|
||||
o.LocalListener = nil
|
||||
}
|
||||
if err != nil {
|
||||
o.Tor.Debugf("Failed closing onion: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
16
vendor/github.com/cretz/bine/tor/log.go
generated
vendored
Normal file
16
vendor/github.com/cretz/bine/tor/log.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
package tor
|
||||
|
||||
import "fmt"
|
||||
|
||||
// DebugEnabled returns true if there is a DebugWriter.
|
||||
func (t *Tor) DebugEnabled() bool {
|
||||
return t.DebugWriter != nil
|
||||
}
|
||||
|
||||
// Debugf writes the formatted string with a newline appended to the DebugWriter
|
||||
// if present.
|
||||
func (t *Tor) Debugf(format string, args ...interface{}) {
|
||||
if w := t.DebugWriter; w != nil {
|
||||
fmt.Fprintf(w, format+"\n", args...)
|
||||
}
|
||||
}
|
453
vendor/github.com/cretz/bine/tor/tor.go
generated
vendored
Normal file
453
vendor/github.com/cretz/bine/tor/tor.go
generated
vendored
Normal file
@ -0,0 +1,453 @@
|
||||
package tor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/cretz/bine/control"
|
||||
|
||||
"github.com/cretz/bine/process"
|
||||
)
|
||||
|
||||
// Tor is the wrapper around the Tor process and control port connection. It
|
||||
// should be created with Start and developers should always call Close when
|
||||
// done.
|
||||
type Tor struct {
|
||||
// Process is the Tor instance that is running.
|
||||
Process process.Process
|
||||
|
||||
// Control is the Tor controller connection.
|
||||
Control *control.Conn
|
||||
|
||||
// ProcessCancelFunc is the context cancellation func for the Tor process.
|
||||
// It is used by Close and should not be called directly. This can be nil.
|
||||
ProcessCancelFunc context.CancelFunc
|
||||
|
||||
// ControlPort is the port that Control is connected on. It is 0 if the
|
||||
// connection is an embedded control connection.
|
||||
ControlPort int
|
||||
|
||||
// DataDir is the path to the data directory that Tor is using.
|
||||
DataDir string
|
||||
|
||||
// DeleteDataDirOnClose is true if, when Close is invoked, the entire
|
||||
// directory will be deleted.
|
||||
DeleteDataDirOnClose bool
|
||||
|
||||
// DebugWriter is the writer used for debug logs, or nil if debug logs
|
||||
// should not be emitted.
|
||||
DebugWriter io.Writer
|
||||
|
||||
// StopProcessOnClose, if true, will attempt to halt the process on close.
|
||||
StopProcessOnClose bool
|
||||
|
||||
// GeoIPCreatedFile is the path, relative to DataDir, that was created from
|
||||
// StartConf.GeoIPFileReader. It is empty if no file was created.
|
||||
GeoIPCreatedFile string
|
||||
|
||||
// GeoIPv6CreatedFile is the path, relative to DataDir, that was created
|
||||
// from StartConf.GeoIPFileReader. It is empty if no file was created.
|
||||
GeoIPv6CreatedFile string
|
||||
}
|
||||
|
||||
// StartConf is the configuration used for Start when starting a Tor instance. A
|
||||
// default instance with no fields set is the default used for Start.
|
||||
type StartConf struct {
|
||||
// ExePath is the path to the Tor executable. If it is not present, "tor" is
|
||||
// used either locally or on the PATH. This is ignored if ProcessCreator is
|
||||
// set.
|
||||
ExePath string
|
||||
|
||||
// ProcessCreator is the override to use a specific process creator. If set,
|
||||
// ExePath is ignored.
|
||||
ProcessCreator process.Creator
|
||||
|
||||
// UseEmbeddedControlConn can be set to true to use
|
||||
// process.Process.EmbeddedControlConn() instead of creating a connection
|
||||
// via ControlPort. Note, this only works when ProcessCreator is an
|
||||
// embedded Tor creator with version >= 0.3.5.x.
|
||||
UseEmbeddedControlConn bool
|
||||
|
||||
// ControlPort is the port to use for the Tor controller. If it is 0, Tor
|
||||
// picks a port for use. This is ignored if UseEmbeddedControlConn is true.
|
||||
ControlPort int
|
||||
|
||||
// DataDir is the directory used by Tor. If it is empty, a temporary
|
||||
// directory is created in TempDataDirBase.
|
||||
DataDir string
|
||||
|
||||
// TempDataDirBase is the parent directory that a temporary data directory
|
||||
// will be created under for use by Tor. This is ignored if DataDir is not
|
||||
// empty. If empty it is assumed to be the current working directory.
|
||||
TempDataDirBase string
|
||||
|
||||
// RetainTempDataDir, if true, will not set the created temporary data
|
||||
// directory to be deleted on close. This is ignored if DataDir is not
|
||||
// empty.
|
||||
RetainTempDataDir bool
|
||||
|
||||
// DisableCookieAuth, if true, will not use the default SAFECOOKIE
|
||||
// authentication mechanism for the Tor controller.
|
||||
DisableCookieAuth bool
|
||||
|
||||
// DisableEagerAuth, if true, will not authenticate on Start.
|
||||
DisableEagerAuth bool
|
||||
|
||||
// EnableNetwork, if true, will connect to the wider Tor network on start.
|
||||
EnableNetwork bool
|
||||
|
||||
// ExtraArgs is the set of extra args passed to the Tor instance when
|
||||
// started.
|
||||
ExtraArgs []string
|
||||
|
||||
// TorrcFile is the torrc file to set on start. If empty, a blank torrc is
|
||||
// created in the data directory and is used instead.
|
||||
TorrcFile string
|
||||
|
||||
// DebugWriter is the writer to use for debug logs, or nil for no debug
|
||||
// logs.
|
||||
DebugWriter io.Writer
|
||||
|
||||
// NoHush if true does not set --hush. By default --hush is set.
|
||||
NoHush bool
|
||||
|
||||
// NoAutoSocksPort if true does not set "--SocksPort auto" as is done by
|
||||
// default. This means the caller could set their own or just let it
|
||||
// default to 9050.
|
||||
NoAutoSocksPort bool
|
||||
|
||||
// GeoIPReader, if present, is called before start to copy geo IP files to
|
||||
// the data directory. Errors are propagated. If the ReadCloser is present,
|
||||
// it is copied to the data dir, overwriting as necessary, and then closed
|
||||
// and the appropriate command line argument is added to reference it. If
|
||||
// both the ReadCloser and error are nil, no copy or command line argument
|
||||
// is used for that version. This is called twice, once with false and once
|
||||
// with true for ipv6.
|
||||
//
|
||||
// This can be set to torutil/geoipembed.GeoIPReader to use an embedded
|
||||
// source.
|
||||
GeoIPFileReader func(ipv6 bool) (io.ReadCloser, error)
|
||||
}
|
||||
|
||||
// Start a Tor instance and connect to it. If ctx is nil, context.Background()
|
||||
// is used. If conf is nil, a default instance is used.
|
||||
func Start(ctx context.Context, conf *StartConf) (*Tor, error) {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
if conf == nil {
|
||||
conf = &StartConf{}
|
||||
}
|
||||
tor := &Tor{DataDir: conf.DataDir, DebugWriter: conf.DebugWriter, StopProcessOnClose: true}
|
||||
// Create the data dir and make it absolute
|
||||
if tor.DataDir == "" {
|
||||
tempBase := conf.TempDataDirBase
|
||||
if tempBase == "" {
|
||||
tempBase = "."
|
||||
}
|
||||
var err error
|
||||
if tempBase, err = filepath.Abs(tempBase); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tor.DataDir, err = ioutil.TempDir(tempBase, "data-dir-"); err != nil {
|
||||
return nil, fmt.Errorf("Unable to create temp data dir: %v", err)
|
||||
}
|
||||
tor.Debugf("Created temp data directory at: %v", tor.DataDir)
|
||||
tor.DeleteDataDirOnClose = !conf.RetainTempDataDir
|
||||
} else if err := os.MkdirAll(tor.DataDir, 0700); err != nil {
|
||||
return nil, fmt.Errorf("Unable to create data dir: %v", err)
|
||||
}
|
||||
|
||||
// !!!! From this point on, we must close tor if we error !!!!
|
||||
|
||||
// Copy geoip stuff if necessary
|
||||
err := tor.copyGeoIPFiles(conf)
|
||||
// Start tor
|
||||
if err == nil {
|
||||
err = tor.startProcess(ctx, conf)
|
||||
}
|
||||
// Connect the controller
|
||||
if err == nil {
|
||||
err = tor.connectController(ctx, conf)
|
||||
}
|
||||
// Attempt eager auth w/ no password
|
||||
if err == nil && !conf.DisableEagerAuth {
|
||||
err = tor.Control.Authenticate("")
|
||||
}
|
||||
// If there was an error, we have to try to close here but it may leave the process open
|
||||
if err != nil {
|
||||
if closeErr := tor.Close(); closeErr != nil {
|
||||
err = fmt.Errorf("Error on start: %v (also got error trying to close: %v)", err, closeErr)
|
||||
}
|
||||
}
|
||||
return tor, err
|
||||
}
|
||||
|
||||
func (t *Tor) copyGeoIPFiles(conf *StartConf) error {
|
||||
if conf.GeoIPFileReader == nil {
|
||||
return nil
|
||||
}
|
||||
if r, err := conf.GeoIPFileReader(false); err != nil {
|
||||
return fmt.Errorf("Unable to read geoip file: %v", err)
|
||||
} else if r != nil {
|
||||
t.GeoIPCreatedFile = "geoip"
|
||||
if err := createFile(filepath.Join(t.DataDir, "geoip"), r); err != nil {
|
||||
return fmt.Errorf("Unable to create geoip file: %v", err)
|
||||
}
|
||||
}
|
||||
if r, err := conf.GeoIPFileReader(true); err != nil {
|
||||
return fmt.Errorf("Unable to read geoip6 file: %v", err)
|
||||
} else if r != nil {
|
||||
t.GeoIPv6CreatedFile = "geoip6"
|
||||
if err := createFile(filepath.Join(t.DataDir, "geoip6"), r); err != nil {
|
||||
return fmt.Errorf("Unable to create geoip6 file: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createFile(to string, from io.ReadCloser) error {
|
||||
f, err := os.Create(to)
|
||||
if err == nil {
|
||||
_, err = io.Copy(f, from)
|
||||
if closeErr := f.Close(); err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
}
|
||||
if closeErr := from.Close(); err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *Tor) startProcess(ctx context.Context, conf *StartConf) error {
|
||||
// Get the creator
|
||||
creator := conf.ProcessCreator
|
||||
if creator == nil {
|
||||
torPath := conf.ExePath
|
||||
if torPath == "" {
|
||||
torPath = "tor"
|
||||
}
|
||||
creator = process.NewCreator(torPath)
|
||||
}
|
||||
// Build the args
|
||||
args := []string{"--DataDirectory", t.DataDir}
|
||||
if !conf.DisableCookieAuth {
|
||||
args = append(args, "--CookieAuthentication", "1")
|
||||
}
|
||||
if !conf.EnableNetwork {
|
||||
args = append(args, "--DisableNetwork", "1")
|
||||
}
|
||||
if !conf.NoHush {
|
||||
args = append(args, "--hush")
|
||||
}
|
||||
if !conf.NoAutoSocksPort {
|
||||
args = append(args, "--SocksPort", "auto")
|
||||
}
|
||||
if t.GeoIPCreatedFile != "" {
|
||||
args = append(args, "--GeoIPFile", filepath.Join(t.DataDir, t.GeoIPCreatedFile))
|
||||
}
|
||||
if t.GeoIPv6CreatedFile != "" {
|
||||
args = append(args, "--GeoIPv6File", filepath.Join(t.DataDir, t.GeoIPv6CreatedFile))
|
||||
}
|
||||
// If there is no Torrc file, create a blank temp one
|
||||
torrcFileName := conf.TorrcFile
|
||||
if torrcFileName == "" {
|
||||
torrcFile, err := ioutil.TempFile(t.DataDir, "torrc-")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
torrcFileName = torrcFile.Name()
|
||||
if err = torrcFile.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
args = append(args, "-f", torrcFileName)
|
||||
// Create file for Tor to write the control port to if it's not told to us and we're not embedded
|
||||
var controlPortFileName string
|
||||
var err error
|
||||
if !conf.UseEmbeddedControlConn {
|
||||
if conf.ControlPort == 0 {
|
||||
controlPortFile, err := ioutil.TempFile(t.DataDir, "control-port-")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
controlPortFileName = controlPortFile.Name()
|
||||
if err = controlPortFile.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
args = append(args, "--ControlPort", "auto", "--ControlPortWriteToFile", controlPortFile.Name())
|
||||
} else {
|
||||
args = append(args, "--ControlPort", strconv.Itoa(conf.ControlPort))
|
||||
}
|
||||
}
|
||||
// Create process creator with args
|
||||
var processCtx context.Context
|
||||
processCtx, t.ProcessCancelFunc = context.WithCancel(ctx)
|
||||
args = append(args, conf.ExtraArgs...)
|
||||
p, err := creator.New(processCtx, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Use the embedded conn if requested
|
||||
if conf.UseEmbeddedControlConn {
|
||||
t.Debugf("Using embedded control connection")
|
||||
conn, err := p.EmbeddedControlConn()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to get embedded control conn: %v", err)
|
||||
}
|
||||
t.Control = control.NewConn(textproto.NewConn(conn))
|
||||
t.Control.DebugWriter = t.DebugWriter
|
||||
}
|
||||
// Start process with the args
|
||||
t.Debugf("Starting tor with args %v", args)
|
||||
if err = p.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
t.Process = p
|
||||
// If not embedded, try a few times to read the control port file if we need to
|
||||
if !conf.UseEmbeddedControlConn {
|
||||
t.ControlPort = conf.ControlPort
|
||||
if t.ControlPort == 0 {
|
||||
ControlPortCheck:
|
||||
for i := 0; i < 10; i++ {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
err = ctx.Err()
|
||||
break ControlPortCheck
|
||||
default:
|
||||
// Try to read the controlport file, or wait a bit
|
||||
var byts []byte
|
||||
if byts, err = ioutil.ReadFile(controlPortFileName); err != nil {
|
||||
break ControlPortCheck
|
||||
} else if t.ControlPort, err = process.ControlPortFromFileContents(string(byts)); err == nil {
|
||||
break ControlPortCheck
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to read control port file: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Tor) connectController(ctx context.Context, conf *StartConf) error {
|
||||
// This doesn't apply if already connected (e.g. using embedded conn)
|
||||
if t.Control != nil {
|
||||
return nil
|
||||
}
|
||||
t.Debugf("Connecting to control port %v", t.ControlPort)
|
||||
textConn, err := textproto.Dial("tcp", "127.0.0.1:"+strconv.Itoa(t.ControlPort))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Control = control.NewConn(textConn)
|
||||
t.Control.DebugWriter = t.DebugWriter
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnableNetwork sets DisableNetwork to 0 and optionally waits for bootstrap to
|
||||
// complete. The context can be nil. If DisableNetwork isnt 1, this does
|
||||
// nothing.
|
||||
func (t *Tor) EnableNetwork(ctx context.Context, wait bool) error {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
// Only enable if DisableNetwork is 1
|
||||
if vals, err := t.Control.GetConf("DisableNetwork"); err != nil {
|
||||
return err
|
||||
} else if len(vals) == 0 || vals[0].Key != "DisableNetwork" || vals[0].Val != "1" {
|
||||
return nil
|
||||
}
|
||||
// Enable the network
|
||||
if err := t.Control.SetConf(control.KeyVals("DisableNetwork", "0")...); err != nil {
|
||||
return nil
|
||||
}
|
||||
// If not waiting, leave
|
||||
if !wait {
|
||||
return nil
|
||||
}
|
||||
// Wait for progress to hit 100
|
||||
_, err := t.Control.EventWait(ctx, []control.EventCode{control.EventCodeStatusClient},
|
||||
func(evt control.Event) (bool, error) {
|
||||
if status, _ := evt.(*control.StatusEvent); status != nil && status.Action == "BOOTSTRAP" {
|
||||
if status.Severity == "NOTICE" && status.Arguments["PROGRESS"] == "100" {
|
||||
return true, nil
|
||||
} else if status.Severity == "ERR" {
|
||||
return false, fmt.Errorf("Failing bootstrapping, Tor warning: %v", status.Arguments["WARNING"])
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// Close sends a halt to the Tor process if it can, closes the controller
|
||||
// connection, and stops the process.
|
||||
func (t *Tor) Close() error {
|
||||
t.Debugf("Closing Tor")
|
||||
errs := []error{}
|
||||
// If controller is authenticated, send the quit signal to the process. Otherwise, just close the controller.
|
||||
sentHalt := false
|
||||
if t.Control != nil {
|
||||
if t.Control.Authenticated && t.StopProcessOnClose {
|
||||
if err := t.Control.Signal("HALT"); err != nil {
|
||||
errs = append(errs, fmt.Errorf("Unable to signal halt: %v", err))
|
||||
} else {
|
||||
sentHalt = true
|
||||
}
|
||||
}
|
||||
// Now close the controller
|
||||
if err := t.Control.Close(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("Unable to close contrlller: %v", err))
|
||||
} else {
|
||||
t.Control = nil
|
||||
}
|
||||
}
|
||||
if t.Process != nil {
|
||||
// If we didn't halt, we have to force kill w/ the cancel func
|
||||
if !sentHalt && t.StopProcessOnClose {
|
||||
t.ProcessCancelFunc()
|
||||
}
|
||||
// Wait for a bit to make sure it stopped
|
||||
errCh := make(chan error, 1)
|
||||
var waitErr error
|
||||
go func() { errCh <- t.Process.Wait() }()
|
||||
select {
|
||||
case waitErr = <-errCh:
|
||||
if waitErr != nil {
|
||||
errs = append(errs, fmt.Errorf("Process wait failed: %v", waitErr))
|
||||
}
|
||||
case <-time.After(300 * time.Millisecond):
|
||||
errs = append(errs, fmt.Errorf("Process did not exit after 300 ms"))
|
||||
}
|
||||
if waitErr == nil {
|
||||
t.Process = nil
|
||||
}
|
||||
}
|
||||
// Get rid of the entire data dir
|
||||
if t.DeleteDataDirOnClose {
|
||||
if err := os.RemoveAll(t.DataDir); err != nil {
|
||||
errs = append(errs, fmt.Errorf("Failed to remove data dir %v: %v", t.DataDir, err))
|
||||
}
|
||||
}
|
||||
// Combine the errors if present
|
||||
if len(errs) == 0 {
|
||||
return nil
|
||||
} else if len(errs) == 1 {
|
||||
t.Debugf("Error while closing Tor: %v", errs[0])
|
||||
return errs[0]
|
||||
}
|
||||
t.Debugf("Errors while closing Tor: %v", errs)
|
||||
return fmt.Errorf("Got %v errors while closing - %v", len(errs), errs)
|
||||
}
|
2
vendor/github.com/cretz/bine/torutil/doc.go
generated
vendored
Normal file
2
vendor/github.com/cretz/bine/torutil/doc.go
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// Package torutil has generic utilities shared across the library.
|
||||
package torutil
|
189
vendor/github.com/cretz/bine/torutil/ed25519/ed25519.go
generated
vendored
Normal file
189
vendor/github.com/cretz/bine/torutil/ed25519/ed25519.go
generated
vendored
Normal file
@ -0,0 +1,189 @@
|
||||
// Package ed25519 implements Tor/BitTorrent-like ed25519 keys.
|
||||
//
|
||||
// See the following stack overflow post for details on why
|
||||
// golang.org/x/crypto/ed25519 can't be used:
|
||||
// https://stackoverflow.com/questions/44810708/ed25519-public-result-is-different
|
||||
package ed25519
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/sha512"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/cretz/bine/torutil/ed25519/internal/edwards25519"
|
||||
"golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
const (
|
||||
// PublicKeySize is the size, in bytes, of public keys as used in this package.
|
||||
PublicKeySize = 32
|
||||
// PrivateKeySize is the size, in bytes, of private keys as used in this package.
|
||||
PrivateKeySize = 64
|
||||
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
||||
SignatureSize = 64
|
||||
)
|
||||
|
||||
// PrivateKey is a 64-byte Ed25519 private key. Unlike
|
||||
// golang.org/x/crypto/ed25519, this is just the digest and does not contain
|
||||
// the public key within it. Instead call PublicKey() or better, call KeyPair()
|
||||
// which stores the precomputed public key.
|
||||
type PrivateKey []byte
|
||||
|
||||
// PublicKey is a 32-byte Ed25519 public key.
|
||||
type PublicKey []byte
|
||||
|
||||
// FromCryptoPrivateKey converts a Go private key to the one in this package.
|
||||
func FromCryptoPrivateKey(key ed25519.PrivateKey) KeyPair {
|
||||
digest := sha512.Sum512(key[:32])
|
||||
digest[0] &= 248
|
||||
digest[31] &= 127
|
||||
digest[31] |= 64
|
||||
return &precomputedKeyPair{PrivateKeyBytes: digest[:], PublicKeyBytes: PublicKey(key[32:])}
|
||||
}
|
||||
|
||||
// FromCryptoPublicKey converts a Go public key to the one in this package.
|
||||
func FromCryptoPublicKey(key ed25519.PublicKey) PublicKey {
|
||||
return PublicKey(key)
|
||||
}
|
||||
|
||||
// KeyPair returns a new key pair with the public key precomputed.
|
||||
func (p PrivateKey) KeyPair() KeyPair {
|
||||
return &precomputedKeyPair{PrivateKeyBytes: p, PublicKeyBytes: p.PublicKey()}
|
||||
}
|
||||
|
||||
// PrivateKey simply returns itself. Implements KeyPair.PrivateKey.
|
||||
func (p PrivateKey) PrivateKey() PrivateKey { return p }
|
||||
|
||||
// Public simply delegates to PublicKey() to satisfy crypto.Signer. This method
|
||||
// does a bit more work than the traditional Go ed25519's private key's Public()
|
||||
// method so developers are encouraged to reuse the result or use KeyPair()
|
||||
// which stores this value.
|
||||
func (p PrivateKey) Public() crypto.PublicKey { return p.PublicKey() }
|
||||
|
||||
// PublicKey generates a public key for this private key. This method does a bit
|
||||
// more work than the traditional Go ed25519's private key's Public() method so
|
||||
// developers are encouraged to reuse the result or use KeyPair() which stores
|
||||
// this value. Implements KeyPair.PublicKey.
|
||||
func (p PrivateKey) PublicKey() PublicKey {
|
||||
var A edwards25519.ExtendedGroupElement
|
||||
var hBytes [32]byte
|
||||
copy(hBytes[:], p[:])
|
||||
edwards25519.GeScalarMultBase(&A, &hBytes)
|
||||
var publicKeyBytes [32]byte
|
||||
A.ToBytes(&publicKeyBytes)
|
||||
return publicKeyBytes[:]
|
||||
}
|
||||
|
||||
// Sign signs the given message with priv. Ed25519 performs two passes over
|
||||
// messages to be signed and therefore cannot handle pre-hashed messages. Thus
|
||||
// opts.HashFunc() must return zero to indicate the message hasn't been hashed.
|
||||
// This can be achieved by passing crypto.Hash(0) as the value for opts.
|
||||
func (p PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) ([]byte, error) {
|
||||
if opts.HashFunc() != crypto.Hash(0) {
|
||||
return nil, errors.New("ed25519: cannot sign hashed message")
|
||||
}
|
||||
return Sign(p, message), nil
|
||||
}
|
||||
|
||||
// Verify simply calls PublicKey().Verify(). Callers are encouraged to instead
|
||||
// store a precomputed KeyPair (via KeyPair() or GenerateKey()) and call Verify
|
||||
// on that.
|
||||
func (p PrivateKey) Verify(message []byte, sig []byte) bool {
|
||||
return p.PublicKey().Verify(message, sig)
|
||||
}
|
||||
|
||||
// Verify simply calls the package-level function Verify().
|
||||
func (p PublicKey) Verify(message []byte, sig []byte) bool {
|
||||
return Verify(p, message, sig)
|
||||
}
|
||||
|
||||
// KeyPair is an interface for types with both keys. While PrivateKey does
|
||||
// implement this, it generates the PublicKey on demand. For better performance,
|
||||
// use the result of GenerateKey directly or call PrivateKey.KeyPair().
|
||||
type KeyPair interface {
|
||||
crypto.Signer
|
||||
PrivateKey() PrivateKey
|
||||
PublicKey() PublicKey
|
||||
Verify(message []byte, sig []byte) bool
|
||||
}
|
||||
|
||||
type precomputedKeyPair struct {
|
||||
PrivateKeyBytes PrivateKey
|
||||
PublicKeyBytes PublicKey
|
||||
}
|
||||
|
||||
func (p *precomputedKeyPair) PrivateKey() PrivateKey { return p.PrivateKeyBytes }
|
||||
func (p *precomputedKeyPair) PublicKey() PublicKey { return p.PublicKeyBytes }
|
||||
func (p *precomputedKeyPair) Public() crypto.PublicKey { return p.PublicKey() }
|
||||
func (p *precomputedKeyPair) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) ([]byte, error) {
|
||||
if opts.HashFunc() != crypto.Hash(0) {
|
||||
return nil, errors.New("ed25519: cannot sign hashed message")
|
||||
}
|
||||
return Sign(p, message), nil
|
||||
}
|
||||
func (p *precomputedKeyPair) Verify(message []byte, sig []byte) bool {
|
||||
return p.PublicKeyBytes.Verify(message, sig)
|
||||
}
|
||||
|
||||
// GenerateKey generates a public/private key pair using entropy from rand.
|
||||
// If rand is nil, crypto/rand.Reader will be used.
|
||||
func GenerateKey(rnd io.Reader) (KeyPair, error) {
|
||||
if rnd == nil {
|
||||
rnd = rand.Reader
|
||||
}
|
||||
rndByts := make([]byte, 32)
|
||||
if _, err := io.ReadFull(rnd, rndByts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
digest := sha512.Sum512(rndByts)
|
||||
digest[0] &= 248
|
||||
digest[31] &= 127
|
||||
digest[31] |= 64
|
||||
return PrivateKey(digest[:]).KeyPair(), nil
|
||||
}
|
||||
|
||||
// Sign signs the message with the given key pair.
|
||||
func Sign(keyPair KeyPair, message []byte) []byte {
|
||||
// Ref: https://stackoverflow.com/questions/44810708/ed25519-public-result-is-different
|
||||
|
||||
var privateKeyA [32]byte
|
||||
copy(privateKeyA[:], keyPair.PrivateKey()) // we need this in an array later
|
||||
var messageDigest, hramDigest [64]byte
|
||||
|
||||
h := sha512.New()
|
||||
h.Write(keyPair.PrivateKey()[32:])
|
||||
h.Write(message)
|
||||
h.Sum(messageDigest[:0])
|
||||
|
||||
var messageDigestReduced [32]byte
|
||||
edwards25519.ScReduce(&messageDigestReduced, &messageDigest)
|
||||
var R edwards25519.ExtendedGroupElement
|
||||
edwards25519.GeScalarMultBase(&R, &messageDigestReduced)
|
||||
|
||||
var encodedR [32]byte
|
||||
R.ToBytes(&encodedR)
|
||||
|
||||
h.Reset()
|
||||
h.Write(encodedR[:])
|
||||
h.Write(keyPair.PublicKey())
|
||||
h.Write(message)
|
||||
h.Sum(hramDigest[:0])
|
||||
var hramDigestReduced [32]byte
|
||||
edwards25519.ScReduce(&hramDigestReduced, &hramDigest)
|
||||
|
||||
var s [32]byte
|
||||
edwards25519.ScMulAdd(&s, &hramDigestReduced, &privateKeyA, &messageDigestReduced)
|
||||
|
||||
signature := make([]byte, 64)
|
||||
copy(signature[:], encodedR[:])
|
||||
copy(signature[32:], s[:])
|
||||
|
||||
return signature
|
||||
}
|
||||
|
||||
// Verify verifies a signed message.
|
||||
func Verify(p PublicKey, message []byte, sig []byte) bool {
|
||||
return ed25519.Verify(ed25519.PublicKey(p), message, sig)
|
||||
}
|
1
vendor/github.com/cretz/bine/torutil/ed25519/internal/edwards25519/README.md
generated
vendored
Normal file
1
vendor/github.com/cretz/bine/torutil/ed25519/internal/edwards25519/README.md
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
This is taken from https://github.com/golang/crypto/tree/1a580b3eff7814fc9b40602fd35256c63b50f491/ed25519/internal/edwards25519
|
1422
vendor/github.com/cretz/bine/torutil/ed25519/internal/edwards25519/const.go
generated
vendored
Normal file
1422
vendor/github.com/cretz/bine/torutil/ed25519/internal/edwards25519/const.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1793
vendor/github.com/cretz/bine/torutil/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
Normal file
1793
vendor/github.com/cretz/bine/torutil/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
85
vendor/github.com/cretz/bine/torutil/key.go
generated
vendored
Normal file
85
vendor/github.com/cretz/bine/torutil/key.go
generated
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
package torutil
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/x509"
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cretz/bine/torutil/ed25519"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
var serviceIDEncoding = base32.StdEncoding.WithPadding(base32.NoPadding)
|
||||
|
||||
// OnionServiceIDFromPrivateKey generates the onion service ID from the given
|
||||
// private key. This panics if the private key is not a 1024-bit
|
||||
// crypto/*rsa.PrivateKey or github.com/cretz/bine/torutil/ed25519.KeyPair.
|
||||
func OnionServiceIDFromPrivateKey(key crypto.PrivateKey) string {
|
||||
switch k := key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return OnionServiceIDFromV2PublicKey(&k.PublicKey)
|
||||
case ed25519.KeyPair:
|
||||
return OnionServiceIDFromV3PublicKey(k.PublicKey())
|
||||
}
|
||||
panic(fmt.Sprintf("Unrecognized private key type: %T", key))
|
||||
}
|
||||
|
||||
// OnionServiceIDFromPublicKey generates the onion service ID from the given
|
||||
// public key. This panics if the public key is not a 1024-bit
|
||||
// crypto/*rsa.PublicKey or github.com/cretz/bine/torutil/ed25519.PublicKey.
|
||||
func OnionServiceIDFromPublicKey(key crypto.PublicKey) string {
|
||||
switch k := key.(type) {
|
||||
case *rsa.PublicKey:
|
||||
return OnionServiceIDFromV2PublicKey(k)
|
||||
case ed25519.PublicKey:
|
||||
return OnionServiceIDFromV3PublicKey(k)
|
||||
}
|
||||
panic(fmt.Sprintf("Unrecognized public key type: %T", key))
|
||||
}
|
||||
|
||||
// OnionServiceIDFromV2PublicKey generates a V2 service ID for the given
|
||||
// RSA-1024 public key. Panics if not a 1024-bit key.
|
||||
func OnionServiceIDFromV2PublicKey(key *rsa.PublicKey) string {
|
||||
if key.N.BitLen() != 1024 {
|
||||
panic("RSA key not 1024 bit")
|
||||
}
|
||||
h := sha1.New()
|
||||
h.Write(x509.MarshalPKCS1PublicKey(key))
|
||||
return strings.ToLower(serviceIDEncoding.EncodeToString(h.Sum(nil)[:10]))
|
||||
}
|
||||
|
||||
// OnionServiceIDFromV3PublicKey generates a V3 service ID for the given
|
||||
// ED25519 public key.
|
||||
func OnionServiceIDFromV3PublicKey(key ed25519.PublicKey) string {
|
||||
checkSum := sha3.Sum256(append(append([]byte(".onion checksum"), key...), 0x03))
|
||||
var keyBytes [35]byte
|
||||
copy(keyBytes[:], key)
|
||||
keyBytes[32] = checkSum[0]
|
||||
keyBytes[33] = checkSum[1]
|
||||
keyBytes[34] = 0x03
|
||||
return strings.ToLower(serviceIDEncoding.EncodeToString(keyBytes[:]))
|
||||
}
|
||||
|
||||
// PublicKeyFromV3OnionServiceID returns a public key for the given service ID
|
||||
// or an error if the service ID is invalid.
|
||||
func PublicKeyFromV3OnionServiceID(id string) (ed25519.PublicKey, error) {
|
||||
byts, err := serviceIDEncoding.DecodeString(strings.ToUpper(id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if len(byts) != 35 {
|
||||
return nil, fmt.Errorf("Invalid id length")
|
||||
} else if byts[34] != 0x03 {
|
||||
return nil, fmt.Errorf("Invalid version")
|
||||
}
|
||||
// Do a checksum check
|
||||
key := ed25519.PublicKey(byts[:32])
|
||||
checkSum := sha3.Sum256(append(append([]byte(".onion checksum"), key...), 0x03))
|
||||
if byts[32] != checkSum[0] || byts[33] != checkSum[1] {
|
||||
return nil, fmt.Errorf("Invalid checksum")
|
||||
}
|
||||
return key, nil
|
||||
}
|
112
vendor/github.com/cretz/bine/torutil/string.go
generated
vendored
Normal file
112
vendor/github.com/cretz/bine/torutil/string.go
generated
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
package torutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PartitionString returns the two parts of a string delimited by the first
|
||||
// occurrence of ch. If ch does not exist, the second string is empty and the
|
||||
// resulting bool is false. Otherwise it is true.
|
||||
func PartitionString(str string, ch byte) (string, string, bool) {
|
||||
index := strings.IndexByte(str, ch)
|
||||
if index == -1 {
|
||||
return str, "", false
|
||||
}
|
||||
return str[:index], str[index+1:], true
|
||||
}
|
||||
|
||||
// PartitionStringFromEnd is same as PartitionString except it delimts by the
|
||||
// last occurrence of ch instead of the first.
|
||||
func PartitionStringFromEnd(str string, ch byte) (string, string, bool) {
|
||||
index := strings.LastIndexByte(str, ch)
|
||||
if index == -1 {
|
||||
return str, "", false
|
||||
}
|
||||
return str[:index], str[index+1:], true
|
||||
}
|
||||
|
||||
// EscapeSimpleQuotedStringIfNeeded calls EscapeSimpleQuotedString only if the
|
||||
// string contains a space, backslash, double quote, newline, or carriage return
|
||||
// character.
|
||||
func EscapeSimpleQuotedStringIfNeeded(str string) string {
|
||||
if strings.ContainsAny(str, " \\\"\r\n") {
|
||||
return EscapeSimpleQuotedString(str)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
var simpleQuotedStringEscapeReplacer = strings.NewReplacer(
|
||||
"\\", "\\\\",
|
||||
"\"", "\\\"",
|
||||
"\r", "\\r",
|
||||
"\n", "\\n",
|
||||
)
|
||||
|
||||
// EscapeSimpleQuotedString calls EscapeSimpleQuotedStringContents and then
|
||||
// surrounds the entire string with double quotes.
|
||||
func EscapeSimpleQuotedString(str string) string {
|
||||
return "\"" + EscapeSimpleQuotedStringContents(str) + "\""
|
||||
}
|
||||
|
||||
// EscapeSimpleQuotedStringContents escapes backslashes, double quotes,
|
||||
// newlines, and carriage returns in str.
|
||||
func EscapeSimpleQuotedStringContents(str string) string {
|
||||
return simpleQuotedStringEscapeReplacer.Replace(str)
|
||||
}
|
||||
|
||||
// UnescapeSimpleQuotedStringIfNeeded calls UnescapeSimpleQuotedString only if
|
||||
// str is surrounded with double quotes.
|
||||
func UnescapeSimpleQuotedStringIfNeeded(str string) (string, error) {
|
||||
if len(str) >= 2 && str[0] == '"' && str[len(str)-1] == '"' {
|
||||
return UnescapeSimpleQuotedString(str)
|
||||
}
|
||||
return str, nil
|
||||
}
|
||||
|
||||
// UnescapeSimpleQuotedString removes surrounding double quotes and calls
|
||||
// UnescapeSimpleQuotedStringContents.
|
||||
func UnescapeSimpleQuotedString(str string) (string, error) {
|
||||
if len(str) < 2 || str[0] != '"' || str[len(str)-1] != '"' {
|
||||
return "", fmt.Errorf("Missing quotes")
|
||||
}
|
||||
return UnescapeSimpleQuotedStringContents(str[1 : len(str)-1])
|
||||
}
|
||||
|
||||
// UnescapeSimpleQuotedStringContents unescapes backslashes, double quotes,
|
||||
// newlines, and carriage returns. Also errors if those aren't escaped.
|
||||
func UnescapeSimpleQuotedStringContents(str string) (string, error) {
|
||||
ret := ""
|
||||
escaping := false
|
||||
for _, c := range str {
|
||||
switch c {
|
||||
case '\\':
|
||||
if escaping {
|
||||
ret += "\\"
|
||||
}
|
||||
escaping = !escaping
|
||||
case '"':
|
||||
if !escaping {
|
||||
return "", fmt.Errorf("Unescaped quote")
|
||||
}
|
||||
ret += "\""
|
||||
escaping = false
|
||||
case '\r', '\n':
|
||||
return "", fmt.Errorf("Unescaped newline or carriage return")
|
||||
default:
|
||||
if escaping {
|
||||
if c == 'r' {
|
||||
ret += "\r"
|
||||
} else if c == 'n' {
|
||||
ret += "\n"
|
||||
} else {
|
||||
return "", fmt.Errorf("Unexpected escape")
|
||||
}
|
||||
} else {
|
||||
ret += string(c)
|
||||
}
|
||||
escaping = false
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
129
vendor/github.com/go-sql-driver/mysql/.travis.yml
generated
vendored
129
vendor/github.com/go-sql-driver/mysql/.travis.yml
generated
vendored
@ -1,129 +0,0 @@
|
||||
sudo: false
|
||||
language: go
|
||||
go:
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
- master
|
||||
|
||||
before_install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
|
||||
before_script:
|
||||
- echo -e "[server]\ninnodb_log_file_size=256MB\ninnodb_buffer_pool_size=512MB\nmax_allowed_packet=16MB" | sudo tee -a /etc/mysql/my.cnf
|
||||
- sudo service mysql restart
|
||||
- .travis/wait_mysql.sh
|
||||
- mysql -e 'create database gotest;'
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- env: DB=MYSQL8
|
||||
sudo: required
|
||||
dist: trusty
|
||||
go: 1.10.x
|
||||
services:
|
||||
- docker
|
||||
before_install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
- docker pull mysql:8.0
|
||||
- docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret
|
||||
mysql:8.0 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1
|
||||
- cp .travis/docker.cnf ~/.my.cnf
|
||||
- .travis/wait_mysql.sh
|
||||
before_script:
|
||||
- export MYSQL_TEST_USER=gotest
|
||||
- export MYSQL_TEST_PASS=secret
|
||||
- export MYSQL_TEST_ADDR=127.0.0.1:3307
|
||||
- export MYSQL_TEST_CONCURRENT=1
|
||||
|
||||
- env: DB=MYSQL57
|
||||
sudo: required
|
||||
dist: trusty
|
||||
go: 1.10.x
|
||||
services:
|
||||
- docker
|
||||
before_install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
- docker pull mysql:5.7
|
||||
- docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret
|
||||
mysql:5.7 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1
|
||||
- cp .travis/docker.cnf ~/.my.cnf
|
||||
- .travis/wait_mysql.sh
|
||||
before_script:
|
||||
- export MYSQL_TEST_USER=gotest
|
||||
- export MYSQL_TEST_PASS=secret
|
||||
- export MYSQL_TEST_ADDR=127.0.0.1:3307
|
||||
- export MYSQL_TEST_CONCURRENT=1
|
||||
|
||||
- env: DB=MARIA55
|
||||
sudo: required
|
||||
dist: trusty
|
||||
go: 1.10.x
|
||||
services:
|
||||
- docker
|
||||
before_install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
- docker pull mariadb:5.5
|
||||
- docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret
|
||||
mariadb:5.5 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1
|
||||
- cp .travis/docker.cnf ~/.my.cnf
|
||||
- .travis/wait_mysql.sh
|
||||
before_script:
|
||||
- export MYSQL_TEST_USER=gotest
|
||||
- export MYSQL_TEST_PASS=secret
|
||||
- export MYSQL_TEST_ADDR=127.0.0.1:3307
|
||||
- export MYSQL_TEST_CONCURRENT=1
|
||||
|
||||
- env: DB=MARIA10_1
|
||||
sudo: required
|
||||
dist: trusty
|
||||
go: 1.10.x
|
||||
services:
|
||||
- docker
|
||||
before_install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
- docker pull mariadb:10.1
|
||||
- docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret
|
||||
mariadb:10.1 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1
|
||||
- cp .travis/docker.cnf ~/.my.cnf
|
||||
- .travis/wait_mysql.sh
|
||||
before_script:
|
||||
- export MYSQL_TEST_USER=gotest
|
||||
- export MYSQL_TEST_PASS=secret
|
||||
- export MYSQL_TEST_ADDR=127.0.0.1:3307
|
||||
- export MYSQL_TEST_CONCURRENT=1
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode10.1
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- mysql
|
||||
update: true
|
||||
go: 1.12.x
|
||||
before_install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
before_script:
|
||||
- echo -e "[server]\ninnodb_log_file_size=256MB\ninnodb_buffer_pool_size=512MB\nmax_allowed_packet=16MB\nlocal_infile=1" >> /usr/local/etc/my.cnf
|
||||
- mysql.server start
|
||||
- mysql -uroot -e 'CREATE USER gotest IDENTIFIED BY "secret"'
|
||||
- mysql -uroot -e 'GRANT ALL ON *.* TO gotest'
|
||||
- mysql -uroot -e 'create database gotest;'
|
||||
- export MYSQL_TEST_USER=gotest
|
||||
- export MYSQL_TEST_PASS=secret
|
||||
- export MYSQL_TEST_ADDR=127.0.0.1:3306
|
||||
- export MYSQL_TEST_CONCURRENT=1
|
||||
|
||||
script:
|
||||
- go test -v -covermode=count -coverprofile=coverage.out
|
||||
- go vet ./...
|
||||
- .travis/gofmt.sh
|
||||
after_script:
|
||||
- $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci
|
21
vendor/github.com/go-sql-driver/mysql/AUTHORS
generated
vendored
21
vendor/github.com/go-sql-driver/mysql/AUTHORS
generated
vendored
@ -13,12 +13,17 @@
|
||||
|
||||
Aaron Hopkins <go-sql-driver at die.net>
|
||||
Achille Roussel <achille.roussel at gmail.com>
|
||||
Alex Snast <alexsn at fb.com>
|
||||
Alexey Palazhchenko <alexey.palazhchenko at gmail.com>
|
||||
Andrew Reid <andrew.reid at tixtrack.com>
|
||||
Animesh Ray <mail.rayanimesh at gmail.com>
|
||||
Arne Hormann <arnehormann at gmail.com>
|
||||
Ariel Mashraki <ariel at mashraki.co.il>
|
||||
Asta Xie <xiemengjun at gmail.com>
|
||||
Bulat Gaifullin <gaifullinbf at gmail.com>
|
||||
Caine Jette <jette at alum.mit.edu>
|
||||
Carlos Nieto <jose.carlos at menteslibres.net>
|
||||
Chris Kirkland <chriskirkland at github.com>
|
||||
Chris Moos <chris at tech9computers.com>
|
||||
Craig Wilson <craiggwilson at gmail.com>
|
||||
Daniel Montoya <dsmontoyam at gmail.com>
|
||||
@ -41,6 +46,7 @@ Ilia Cimpoes <ichimpoesh at gmail.com>
|
||||
INADA Naoki <songofacandy at gmail.com>
|
||||
Jacek Szwec <szwec.jacek at gmail.com>
|
||||
James Harr <james.harr at gmail.com>
|
||||
Janek Vedock <janekvedock at comcast.net>
|
||||
Jeff Hodges <jeff at somethingsimilar.com>
|
||||
Jeffrey Charles <jeffreycharles at gmail.com>
|
||||
Jerome Meyer <jxmeyer at gmail.com>
|
||||
@ -52,14 +58,17 @@ Julien Schmidt <go-sql-driver at julienschmidt.com>
|
||||
Justin Li <jli at j-li.net>
|
||||
Justin Nuß <nuss.justin at gmail.com>
|
||||
Kamil Dziedzic <kamil at klecza.pl>
|
||||
Kei Kamikawa <x00.x7f.x86 at gmail.com>
|
||||
Kevin Malachowski <kevin at chowski.com>
|
||||
Kieron Woodhouse <kieron.woodhouse at infosum.com>
|
||||
Lance Tian <lance6716 at gmail.com>
|
||||
Lennart Rudolph <lrudolph at hmc.edu>
|
||||
Leonardo YongUk Kim <dalinaum at gmail.com>
|
||||
Linh Tran Tuan <linhduonggnu at gmail.com>
|
||||
Lion Yang <lion at aosc.xyz>
|
||||
Luca Looz <luca.looz92 at gmail.com>
|
||||
Lucas Liu <extrafliu at gmail.com>
|
||||
Lunny Xiao <xiaolunwen at gmail.com>
|
||||
Luke Scott <luke at webconnex.com>
|
||||
Maciej Zimnoch <maciej.zimnoch at codilime.com>
|
||||
Michael Woolnough <michael.woolnough at gmail.com>
|
||||
@ -69,31 +78,42 @@ Olivier Mengué <dolmen at cpan.org>
|
||||
oscarzhao <oscarzhaosl at gmail.com>
|
||||
Paul Bonser <misterpib at gmail.com>
|
||||
Peter Schultz <peter.schultz at classmarkets.com>
|
||||
Phil Porada <philporada at gmail.com>
|
||||
Rebecca Chin <rchin at pivotal.io>
|
||||
Reed Allman <rdallman10 at gmail.com>
|
||||
Richard Wilkes <wilkes at me.com>
|
||||
Robert Russell <robert at rrbrussell.com>
|
||||
Runrioter Wung <runrioter at gmail.com>
|
||||
Samantha Frank <hello at entropy.cat>
|
||||
Santhosh Kumar Tekuri <santhosh.tekuri at gmail.com>
|
||||
Sho Iizuka <sho.i518 at gmail.com>
|
||||
Sho Ikeda <suicaicoca at gmail.com>
|
||||
Shuode Li <elemount at qq.com>
|
||||
Simon J Mudd <sjmudd at pobox.com>
|
||||
Soroush Pour <me at soroushjp.com>
|
||||
Stan Putrya <root.vagner at gmail.com>
|
||||
Stanley Gunawan <gunawan.stanley at gmail.com>
|
||||
Steven Hartland <steven.hartland at multiplay.co.uk>
|
||||
Tan Jinhua <312841925 at qq.com>
|
||||
Thomas Wodarek <wodarekwebpage at gmail.com>
|
||||
Tim Ruffles <timruffles at gmail.com>
|
||||
Tom Jenkinson <tom at tjenkinson.me>
|
||||
Vladimir Kovpak <cn007b at gmail.com>
|
||||
Vladyslav Zhelezniak <zhvladi at gmail.com>
|
||||
Xiangyu Hu <xiangyu.hu at outlook.com>
|
||||
Xiaobing Jiang <s7v7nislands at gmail.com>
|
||||
Xiuming Chen <cc at cxm.cc>
|
||||
Xuehong Chan <chanxuehong at gmail.com>
|
||||
Zhenye Xie <xiezhenye at gmail.com>
|
||||
Zhixin Wen <john.wenzhixin at gmail.com>
|
||||
Ziheng Lyu <zihenglv at gmail.com>
|
||||
|
||||
# Organizations
|
||||
|
||||
Barracuda Networks, Inc.
|
||||
Counting Ltd.
|
||||
DigitalOcean Inc.
|
||||
dyves labs AG
|
||||
Facebook Inc.
|
||||
GitHub Inc.
|
||||
Google Inc.
|
||||
@ -103,3 +123,4 @@ Multiplay Ltd.
|
||||
Percona LLC
|
||||
Pivotal Inc.
|
||||
Stripe Inc.
|
||||
Zendesk Inc.
|
||||
|
60
vendor/github.com/go-sql-driver/mysql/CHANGELOG.md
generated
vendored
60
vendor/github.com/go-sql-driver/mysql/CHANGELOG.md
generated
vendored
@ -1,3 +1,63 @@
|
||||
## Version 1.7.1 (2023-04-25)
|
||||
|
||||
Changes:
|
||||
|
||||
- bump actions/checkout@v3 and actions/setup-go@v3 (#1375)
|
||||
- Add go1.20 and mariadb10.11 to the testing matrix (#1403)
|
||||
- Increase default maxAllowedPacket size. (#1411)
|
||||
|
||||
Bugfixes:
|
||||
|
||||
- Use SET syntax as specified in the MySQL documentation (#1402)
|
||||
|
||||
|
||||
## Version 1.7 (2022-11-29)
|
||||
|
||||
Changes:
|
||||
|
||||
- Drop support of Go 1.12 (#1211)
|
||||
- Refactoring `(*textRows).readRow` in a more clear way (#1230)
|
||||
- util: Reduce boundary check in escape functions. (#1316)
|
||||
- enhancement for mysqlConn handleAuthResult (#1250)
|
||||
|
||||
New Features:
|
||||
|
||||
- support Is comparison on MySQLError (#1210)
|
||||
- return unsigned in database type name when necessary (#1238)
|
||||
- Add API to express like a --ssl-mode=PREFERRED MySQL client (#1370)
|
||||
- Add SQLState to MySQLError (#1321)
|
||||
|
||||
Bugfixes:
|
||||
|
||||
- Fix parsing 0 year. (#1257)
|
||||
|
||||
|
||||
## Version 1.6 (2021-04-01)
|
||||
|
||||
Changes:
|
||||
|
||||
- Migrate the CI service from travis-ci to GitHub Actions (#1176, #1183, #1190)
|
||||
- `NullTime` is deprecated (#960, #1144)
|
||||
- Reduce allocations when building SET command (#1111)
|
||||
- Performance improvement for time formatting (#1118)
|
||||
- Performance improvement for time parsing (#1098, #1113)
|
||||
|
||||
New Features:
|
||||
|
||||
- Implement `driver.Validator` interface (#1106, #1174)
|
||||
- Support returning `uint64` from `Valuer` in `ConvertValue` (#1143)
|
||||
- Add `json.RawMessage` for converter and prepared statement (#1059)
|
||||
- Interpolate `json.RawMessage` as `string` (#1058)
|
||||
- Implements `CheckNamedValue` (#1090)
|
||||
|
||||
Bugfixes:
|
||||
|
||||
- Stop rounding times (#1121, #1172)
|
||||
- Put zero filler into the SSL handshake packet (#1066)
|
||||
- Fix checking cancelled connections back into the connection pool (#1095)
|
||||
- Fix remove last 0 byte for mysql_old_password when password is empty (#1133)
|
||||
|
||||
|
||||
## Version 1.5 (2020-01-07)
|
||||
|
||||
Changes:
|
||||
|
62
vendor/github.com/go-sql-driver/mysql/README.md
generated
vendored
62
vendor/github.com/go-sql-driver/mysql/README.md
generated
vendored
@ -35,12 +35,12 @@ A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) pac
|
||||
* Supports queries larger than 16MB
|
||||
* Full [`sql.RawBytes`](https://golang.org/pkg/database/sql/#RawBytes) support.
|
||||
* Intelligent `LONG DATA` handling in prepared statements
|
||||
* Secure `LOAD DATA LOCAL INFILE` support with file Whitelisting and `io.Reader` support
|
||||
* Secure `LOAD DATA LOCAL INFILE` support with file allowlisting and `io.Reader` support
|
||||
* Optional `time.Time` parsing
|
||||
* Optional placeholder interpolation
|
||||
|
||||
## Requirements
|
||||
* Go 1.10 or higher. We aim to support the 3 latest versions of Go.
|
||||
* Go 1.13 or higher. We aim to support the 3 latest versions of Go.
|
||||
* MySQL (4.1+), MariaDB, Percona Server, Google CloudSQL or Sphinx (2.2.3+)
|
||||
|
||||
---------------------------------------
|
||||
@ -56,15 +56,37 @@ Make sure [Git is installed](https://git-scm.com/downloads) on your machine and
|
||||
_Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](https://golang.org/pkg/database/sql/) API then.
|
||||
|
||||
Use `mysql` as `driverName` and a valid [DSN](#dsn-data-source-name) as `dataSourceName`:
|
||||
|
||||
```go
|
||||
import "database/sql"
|
||||
import _ "github.com/go-sql-driver/mysql"
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
// ...
|
||||
|
||||
db, err := sql.Open("mysql", "user:password@/dbname")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// See "Important settings" section.
|
||||
db.SetConnMaxLifetime(time.Minute * 3)
|
||||
db.SetMaxOpenConns(10)
|
||||
db.SetMaxIdleConns(10)
|
||||
```
|
||||
|
||||
[Examples are available in our Wiki](https://github.com/go-sql-driver/mysql/wiki/Examples "Go-MySQL-Driver Examples").
|
||||
|
||||
### Important settings
|
||||
|
||||
`db.SetConnMaxLifetime()` is required to ensure connections are closed by the driver safely before connection is closed by MySQL server, OS, or other middlewares. Since some middlewares close idle connections by 5 minutes, we recommend timeout shorter than 5 minutes. This setting helps load balancing and changing system variables too.
|
||||
|
||||
`db.SetMaxOpenConns()` is highly recommended to limit the number of connection used by the application. There is no recommended limit number because it depends on application and MySQL server.
|
||||
|
||||
`db.SetMaxIdleConns()` is recommended to be set same to `db.SetMaxOpenConns()`. When it is smaller than `SetMaxOpenConns()`, connections can be opened and closed much more frequently than you expect. Idle connections can be closed by the `db.SetConnMaxLifetime()`. If you want to close idle connections more rapidly, you can use `db.SetConnMaxIdleTime()` since Go 1.15.
|
||||
|
||||
|
||||
### DSN (Data Source Name)
|
||||
|
||||
@ -122,7 +144,7 @@ Valid Values: true, false
|
||||
Default: false
|
||||
```
|
||||
|
||||
`allowAllFiles=true` disables the file Whitelist for `LOAD DATA LOCAL INFILE` and allows *all* files.
|
||||
`allowAllFiles=true` disables the file allowlist for `LOAD DATA LOCAL INFILE` and allows *all* files.
|
||||
[*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)
|
||||
|
||||
##### `allowCleartextPasswords`
|
||||
@ -133,7 +155,18 @@ Valid Values: true, false
|
||||
Default: false
|
||||
```
|
||||
|
||||
`allowCleartextPasswords=true` allows using the [cleartext client side plugin](http://dev.mysql.com/doc/en/cleartext-authentication-plugin.html) if required by an account, such as one defined with the [PAM authentication plugin](http://dev.mysql.com/doc/en/pam-authentication-plugin.html). Sending passwords in clear text may be a security problem in some configurations. To avoid problems if there is any possibility that the password would be intercepted, clients should connect to MySQL Server using a method that protects the password. Possibilities include [TLS / SSL](#tls), IPsec, or a private network.
|
||||
`allowCleartextPasswords=true` allows using the [cleartext client side plugin](https://dev.mysql.com/doc/en/cleartext-pluggable-authentication.html) if required by an account, such as one defined with the [PAM authentication plugin](http://dev.mysql.com/doc/en/pam-authentication-plugin.html). Sending passwords in clear text may be a security problem in some configurations. To avoid problems if there is any possibility that the password would be intercepted, clients should connect to MySQL Server using a method that protects the password. Possibilities include [TLS / SSL](#tls), IPsec, or a private network.
|
||||
|
||||
|
||||
##### `allowFallbackToPlaintext`
|
||||
|
||||
```
|
||||
Type: bool
|
||||
Valid Values: true, false
|
||||
Default: false
|
||||
```
|
||||
|
||||
`allowFallbackToPlaintext=true` acts like a `--ssl-mode=PREFERRED` MySQL client as described in [Command Options for Connecting to the Server](https://dev.mysql.com/doc/refman/5.7/en/connection-options.html#option_general_ssl-mode)
|
||||
|
||||
##### `allowNativePasswords`
|
||||
|
||||
@ -230,7 +263,7 @@ Default: false
|
||||
|
||||
If `interpolateParams` is true, placeholders (`?`) in calls to `db.Query()` and `db.Exec()` are interpolated into a single query string with given parameters. This reduces the number of roundtrips, since the driver has to prepare a statement, execute it with given parameters and close the statement again with `interpolateParams=false`.
|
||||
|
||||
*This can not be used together with the multibyte encodings BIG5, CP932, GB2312, GBK or SJIS. These are blacklisted as they may [introduce a SQL injection vulnerability](http://stackoverflow.com/a/12118602/3430118)!*
|
||||
*This can not be used together with the multibyte encodings BIG5, CP932, GB2312, GBK or SJIS. These are rejected as they may [introduce a SQL injection vulnerability](http://stackoverflow.com/a/12118602/3430118)!*
|
||||
|
||||
##### `loc`
|
||||
|
||||
@ -249,10 +282,10 @@ Please keep in mind, that param values must be [url.QueryEscape](https://golang.
|
||||
##### `maxAllowedPacket`
|
||||
```
|
||||
Type: decimal number
|
||||
Default: 4194304
|
||||
Default: 64*1024*1024
|
||||
```
|
||||
|
||||
Max packet size allowed in bytes. The default value is 4 MiB and should be adjusted to match the server settings. `maxAllowedPacket=0` can be used to automatically fetch the `max_allowed_packet` variable from server *on every connection*.
|
||||
Max packet size allowed in bytes. The default value is 64 MiB and should be adjusted to match the server settings. `maxAllowedPacket=0` can be used to automatically fetch the `max_allowed_packet` variable from server *on every connection*.
|
||||
|
||||
##### `multiStatements`
|
||||
|
||||
@ -376,7 +409,7 @@ Rules:
|
||||
Examples:
|
||||
* `autocommit=1`: `SET autocommit=1`
|
||||
* [`time_zone=%27Europe%2FParis%27`](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html): `SET time_zone='Europe/Paris'`
|
||||
* [`tx_isolation=%27REPEATABLE-READ%27`](https://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_tx_isolation): `SET tx_isolation='REPEATABLE-READ'`
|
||||
* [`transaction_isolation=%27REPEATABLE-READ%27`](https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_transaction_isolation): `SET transaction_isolation='REPEATABLE-READ'`
|
||||
|
||||
|
||||
#### Examples
|
||||
@ -432,7 +465,7 @@ user:password@/
|
||||
The connection pool is managed by Go's database/sql package. For details on how to configure the size of the pool and how long connections stay in the pool see `*DB.SetMaxOpenConns`, `*DB.SetMaxIdleConns`, and `*DB.SetConnMaxLifetime` in the [database/sql documentation](https://golang.org/pkg/database/sql/). The read, write, and dial timeouts for each individual connection are configured with the DSN parameters [`readTimeout`](#readtimeout), [`writeTimeout`](#writetimeout), and [`timeout`](#timeout), respectively.
|
||||
|
||||
## `ColumnType` Support
|
||||
This driver supports the [`ColumnType` interface](https://golang.org/pkg/database/sql/#ColumnType) introduced in Go 1.8, with the exception of [`ColumnType.Length()`](https://golang.org/pkg/database/sql/#ColumnType.Length), which is currently not supported.
|
||||
This driver supports the [`ColumnType` interface](https://golang.org/pkg/database/sql/#ColumnType) introduced in Go 1.8, with the exception of [`ColumnType.Length()`](https://golang.org/pkg/database/sql/#ColumnType.Length), which is currently not supported. All Unsigned database type names will be returned `UNSIGNED ` with `INT`, `TINYINT`, `SMALLINT`, `BIGINT`.
|
||||
|
||||
## `context.Context` Support
|
||||
Go 1.8 added `database/sql` support for `context.Context`. This driver supports query timeouts and cancellation via contexts.
|
||||
@ -445,7 +478,7 @@ For this feature you need direct access to the package. Therefore you must chang
|
||||
import "github.com/go-sql-driver/mysql"
|
||||
```
|
||||
|
||||
Files must be whitelisted by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the Whitelist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)).
|
||||
Files must be explicitly allowed by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the allowlist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)).
|
||||
|
||||
To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::<name>` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore.
|
||||
|
||||
@ -459,8 +492,6 @@ However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` v
|
||||
|
||||
**Caution:** As of Go 1.1, this makes `time.Time` the only variable type you can scan `DATE` and `DATETIME` values into. This breaks for example [`sql.RawBytes` support](https://github.com/go-sql-driver/mysql/wiki/Examples#rawbytes).
|
||||
|
||||
Alternatively you can use the [`NullTime`](https://godoc.org/github.com/go-sql-driver/mysql#NullTime) type as the scan destination, which works with both `time.Time` and `string` / `[]byte`.
|
||||
|
||||
|
||||
### Unicode support
|
||||
Since version 1.5 Go-MySQL-Driver automatically uses the collation ` utf8mb4_general_ci` by default.
|
||||
@ -477,7 +508,7 @@ To run the driver tests you may need to adjust the configuration. See the [Testi
|
||||
Go-MySQL-Driver is not feature-complete yet. Your help is very appreciated.
|
||||
If you want to contribute, you can work on an [open issue](https://github.com/go-sql-driver/mysql/issues?state=open) or review a [pull request](https://github.com/go-sql-driver/mysql/pulls).
|
||||
|
||||
See the [Contribution Guidelines](https://github.com/go-sql-driver/mysql/blob/master/CONTRIBUTING.md) for details.
|
||||
See the [Contribution Guidelines](https://github.com/go-sql-driver/mysql/blob/master/.github/CONTRIBUTING.md) for details.
|
||||
|
||||
---------------------------------------
|
||||
|
||||
@ -498,4 +529,3 @@ Please read the [MPL 2.0 FAQ](https://www.mozilla.org/en-US/MPL/2.0/FAQ/) if you
|
||||
You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE).
|
||||
|
||||
![Go Gopher and MySQL Dolphin](https://raw.github.com/wiki/go-sql-driver/mysql/go-mysql-driver_m.jpg "Golang Gopher transporting the MySQL Dolphin in a wheelbarrow")
|
||||
|
||||
|
19
vendor/github.com/go-sql-driver/mysql/atomic_bool.go
generated
vendored
Normal file
19
vendor/github.com/go-sql-driver/mysql/atomic_bool.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package.
|
||||
//
|
||||
// Copyright 2022 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//go:build go1.19
|
||||
// +build go1.19
|
||||
|
||||
package mysql
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
/******************************************************************************
|
||||
* Sync utils *
|
||||
******************************************************************************/
|
||||
|
||||
type atomicBool = atomic.Bool
|
47
vendor/github.com/go-sql-driver/mysql/atomic_bool_go118.go
generated
vendored
Normal file
47
vendor/github.com/go-sql-driver/mysql/atomic_bool_go118.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package.
|
||||
//
|
||||
// Copyright 2022 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//go:build !go1.19
|
||||
// +build !go1.19
|
||||
|
||||
package mysql
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
/******************************************************************************
|
||||
* Sync utils *
|
||||
******************************************************************************/
|
||||
|
||||
// atomicBool is an implementation of atomic.Bool for older version of Go.
|
||||
// it is a wrapper around uint32 for usage as a boolean value with
|
||||
// atomic access.
|
||||
type atomicBool struct {
|
||||
_ noCopy
|
||||
value uint32
|
||||
}
|
||||
|
||||
// Load returns whether the current boolean value is true
|
||||
func (ab *atomicBool) Load() bool {
|
||||
return atomic.LoadUint32(&ab.value) > 0
|
||||
}
|
||||
|
||||
// Store sets the value of the bool regardless of the previous value
|
||||
func (ab *atomicBool) Store(value bool) {
|
||||
if value {
|
||||
atomic.StoreUint32(&ab.value, 1)
|
||||
} else {
|
||||
atomic.StoreUint32(&ab.value, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// Swap sets the value of the bool and returns the old value.
|
||||
func (ab *atomicBool) Swap(value bool) bool {
|
||||
if value {
|
||||
return atomic.SwapUint32(&ab.value, 1) > 0
|
||||
}
|
||||
return atomic.SwapUint32(&ab.value, 0) > 0
|
||||
}
|
69
vendor/github.com/go-sql-driver/mysql/auth.go
generated
vendored
69
vendor/github.com/go-sql-driver/mysql/auth.go
generated
vendored
@ -15,6 +15,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@ -32,27 +33,26 @@ var (
|
||||
// Note: The provided rsa.PublicKey instance is exclusively owned by the driver
|
||||
// after registering it and may not be modified.
|
||||
//
|
||||
// data, err := ioutil.ReadFile("mykey.pem")
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// data, err := ioutil.ReadFile("mykey.pem")
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// block, _ := pem.Decode(data)
|
||||
// if block == nil || block.Type != "PUBLIC KEY" {
|
||||
// log.Fatal("failed to decode PEM block containing public key")
|
||||
// }
|
||||
// block, _ := pem.Decode(data)
|
||||
// if block == nil || block.Type != "PUBLIC KEY" {
|
||||
// log.Fatal("failed to decode PEM block containing public key")
|
||||
// }
|
||||
//
|
||||
// pub, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// if rsaPubKey, ok := pub.(*rsa.PublicKey); ok {
|
||||
// mysql.RegisterServerPubKey("mykey", rsaPubKey)
|
||||
// } else {
|
||||
// log.Fatal("not a RSA public key")
|
||||
// }
|
||||
// pub, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// if rsaPubKey, ok := pub.(*rsa.PublicKey); ok {
|
||||
// mysql.RegisterServerPubKey("mykey", rsaPubKey)
|
||||
// } else {
|
||||
// log.Fatal("not a RSA public key")
|
||||
// }
|
||||
func RegisterServerPubKey(name string, pubKey *rsa.PublicKey) {
|
||||
serverPubKeyLock.Lock()
|
||||
if serverPubKeyRegistry == nil {
|
||||
@ -136,10 +136,6 @@ func pwHash(password []byte) (result [2]uint32) {
|
||||
|
||||
// Hash password using insecure pre 4.1 method
|
||||
func scrambleOldPassword(scramble []byte, password string) []byte {
|
||||
if len(password) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
scramble = scramble[:8]
|
||||
|
||||
hashPw := pwHash([]byte(password))
|
||||
@ -247,6 +243,9 @@ func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, error) {
|
||||
if !mc.cfg.AllowOldPasswords {
|
||||
return nil, ErrOldPassword
|
||||
}
|
||||
if len(mc.cfg.Passwd) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
// Note: there are edge cases where this should work but doesn't;
|
||||
// this is currently "wontfix":
|
||||
// https://github.com/go-sql-driver/mysql/issues/184
|
||||
@ -274,7 +273,9 @@ func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, error) {
|
||||
if len(mc.cfg.Passwd) == 0 {
|
||||
return []byte{0}, nil
|
||||
}
|
||||
if mc.cfg.tls != nil || mc.cfg.Net == "unix" {
|
||||
// unlike caching_sha2_password, sha256_password does not accept
|
||||
// cleartext password on unix transport.
|
||||
if mc.cfg.TLS != nil {
|
||||
// write cleartext auth packet
|
||||
return append([]byte(mc.cfg.Passwd), 0), nil
|
||||
}
|
||||
@ -350,7 +351,7 @@ func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error {
|
||||
}
|
||||
|
||||
case cachingSha2PasswordPerformFullAuthentication:
|
||||
if mc.cfg.tls != nil || mc.cfg.Net == "unix" {
|
||||
if mc.cfg.TLS != nil || mc.cfg.Net == "unix" {
|
||||
// write cleartext auth packet
|
||||
err = mc.writeAuthSwitchPacket(append([]byte(mc.cfg.Passwd), 0))
|
||||
if err != nil {
|
||||
@ -365,14 +366,24 @@ func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error {
|
||||
return err
|
||||
}
|
||||
data[4] = cachingSha2PasswordRequestPublicKey
|
||||
mc.writePacket(data)
|
||||
err = mc.writePacket(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// parse public key
|
||||
if data, err = mc.readPacket(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(data[1:])
|
||||
if data[0] != iAuthMoreData {
|
||||
return fmt.Errorf("unexpect resp from server for caching_sha2_password perform full authentication")
|
||||
}
|
||||
|
||||
// parse public key
|
||||
block, rest := pem.Decode(data[1:])
|
||||
if block == nil {
|
||||
return fmt.Errorf("No Pem data found, data: %s", rest)
|
||||
}
|
||||
pkix, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -401,6 +412,10 @@ func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error {
|
||||
return nil // auth successful
|
||||
default:
|
||||
block, _ := pem.Decode(authData)
|
||||
if block == nil {
|
||||
return fmt.Errorf("no Pem data found, data: %s", authData)
|
||||
}
|
||||
|
||||
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
|
5
vendor/github.com/go-sql-driver/mysql/collations.go
generated
vendored
5
vendor/github.com/go-sql-driver/mysql/collations.go
generated
vendored
@ -13,7 +13,8 @@ const binaryCollation = "binary"
|
||||
|
||||
// A list of available collations mapped to the internal ID.
|
||||
// To update this map use the following MySQL query:
|
||||
// SELECT COLLATION_NAME, ID FROM information_schema.COLLATIONS WHERE ID<256 ORDER BY ID
|
||||
//
|
||||
// SELECT COLLATION_NAME, ID FROM information_schema.COLLATIONS WHERE ID<256 ORDER BY ID
|
||||
//
|
||||
// Handshake packet have only 1 byte for collation_id. So we can't use collations with ID > 255.
|
||||
//
|
||||
@ -247,7 +248,7 @@ var collations = map[string]byte{
|
||||
"utf8mb4_0900_ai_ci": 255,
|
||||
}
|
||||
|
||||
// A blacklist of collations which is unsafe to interpolate parameters.
|
||||
// A denylist of collations which is unsafe to interpolate parameters.
|
||||
// These multibyte encodings may contains 0x5c (`\`) in their trailing bytes.
|
||||
var unsafeCollations = map[string]bool{
|
||||
"big5_chinese_ci": true,
|
||||
|
1
vendor/github.com/go-sql-driver/mysql/conncheck.go
generated
vendored
1
vendor/github.com/go-sql-driver/mysql/conncheck.go
generated
vendored
@ -6,6 +6,7 @@
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
//go:build linux || darwin || dragonfly || freebsd || netbsd || openbsd || solaris || illumos
|
||||
// +build linux darwin dragonfly freebsd netbsd openbsd solaris illumos
|
||||
|
||||
package mysql
|
||||
|
1
vendor/github.com/go-sql-driver/mysql/conncheck_dummy.go
generated
vendored
1
vendor/github.com/go-sql-driver/mysql/conncheck_dummy.go
generated
vendored
@ -6,6 +6,7 @@
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
//go:build !linux && !darwin && !dragonfly && !freebsd && !netbsd && !openbsd && !solaris && !illumos
|
||||
// +build !linux,!darwin,!dragonfly,!freebsd,!netbsd,!openbsd,!solaris,!illumos
|
||||
|
||||
package mysql
|
||||
|
103
vendor/github.com/go-sql-driver/mysql/connection.go
generated
vendored
103
vendor/github.com/go-sql-driver/mysql/connection.go
generated
vendored
@ -12,6 +12,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
@ -46,9 +47,10 @@ type mysqlConn struct {
|
||||
|
||||
// Handles parameters set in DSN after the connection is established
|
||||
func (mc *mysqlConn) handleParams() (err error) {
|
||||
var cmdSet strings.Builder
|
||||
for param, val := range mc.cfg.Params {
|
||||
switch param {
|
||||
// Charset
|
||||
// Charset: character_set_connection, character_set_client, character_set_results
|
||||
case "charset":
|
||||
charsets := strings.Split(val, ",")
|
||||
for i := range charsets {
|
||||
@ -62,12 +64,25 @@ func (mc *mysqlConn) handleParams() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// System Vars
|
||||
// Other system vars accumulated in a single SET command
|
||||
default:
|
||||
err = mc.exec("SET " + param + "=" + val + "")
|
||||
if err != nil {
|
||||
return
|
||||
if cmdSet.Len() == 0 {
|
||||
// Heuristic: 29 chars for each other key=value to reduce reallocations
|
||||
cmdSet.Grow(4 + len(param) + 1 + len(val) + 30*(len(mc.cfg.Params)-1))
|
||||
cmdSet.WriteString("SET ")
|
||||
} else {
|
||||
cmdSet.WriteString(", ")
|
||||
}
|
||||
cmdSet.WriteString(param)
|
||||
cmdSet.WriteString(" = ")
|
||||
cmdSet.WriteString(val)
|
||||
}
|
||||
}
|
||||
|
||||
if cmdSet.Len() > 0 {
|
||||
err = mc.exec(cmdSet.String())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +104,7 @@ func (mc *mysqlConn) Begin() (driver.Tx, error) {
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) {
|
||||
if mc.closed.IsSet() {
|
||||
if mc.closed.Load() {
|
||||
errLog.Print(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
@ -108,7 +123,7 @@ func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) {
|
||||
|
||||
func (mc *mysqlConn) Close() (err error) {
|
||||
// Makes Close idempotent
|
||||
if !mc.closed.IsSet() {
|
||||
if !mc.closed.Load() {
|
||||
err = mc.writeCommandPacket(comQuit)
|
||||
}
|
||||
|
||||
@ -122,7 +137,7 @@ func (mc *mysqlConn) Close() (err error) {
|
||||
// is called before auth or on auth failure because MySQL will have already
|
||||
// closed the network connection.
|
||||
func (mc *mysqlConn) cleanup() {
|
||||
if !mc.closed.TrySet(true) {
|
||||
if mc.closed.Swap(true) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -137,7 +152,7 @@ func (mc *mysqlConn) cleanup() {
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) error() error {
|
||||
if mc.closed.IsSet() {
|
||||
if mc.closed.Load() {
|
||||
if err := mc.canceled.Value(); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -147,7 +162,7 @@ func (mc *mysqlConn) error() error {
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
|
||||
if mc.closed.IsSet() {
|
||||
if mc.closed.Load() {
|
||||
errLog.Print(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
@ -230,47 +245,21 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
|
||||
if v.IsZero() {
|
||||
buf = append(buf, "'0000-00-00'"...)
|
||||
} else {
|
||||
v := v.In(mc.cfg.Loc)
|
||||
v = v.Add(time.Nanosecond * 500) // To round under microsecond
|
||||
year := v.Year()
|
||||
year100 := year / 100
|
||||
year1 := year % 100
|
||||
month := v.Month()
|
||||
day := v.Day()
|
||||
hour := v.Hour()
|
||||
minute := v.Minute()
|
||||
second := v.Second()
|
||||
micro := v.Nanosecond() / 1000
|
||||
|
||||
buf = append(buf, []byte{
|
||||
'\'',
|
||||
digits10[year100], digits01[year100],
|
||||
digits10[year1], digits01[year1],
|
||||
'-',
|
||||
digits10[month], digits01[month],
|
||||
'-',
|
||||
digits10[day], digits01[day],
|
||||
' ',
|
||||
digits10[hour], digits01[hour],
|
||||
':',
|
||||
digits10[minute], digits01[minute],
|
||||
':',
|
||||
digits10[second], digits01[second],
|
||||
}...)
|
||||
|
||||
if micro != 0 {
|
||||
micro10000 := micro / 10000
|
||||
micro100 := micro / 100 % 100
|
||||
micro1 := micro % 100
|
||||
buf = append(buf, []byte{
|
||||
'.',
|
||||
digits10[micro10000], digits01[micro10000],
|
||||
digits10[micro100], digits01[micro100],
|
||||
digits10[micro1], digits01[micro1],
|
||||
}...)
|
||||
buf = append(buf, '\'')
|
||||
buf, err = appendDateTime(buf, v.In(mc.cfg.Loc))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
buf = append(buf, '\'')
|
||||
}
|
||||
case json.RawMessage:
|
||||
buf = append(buf, '\'')
|
||||
if mc.status&statusNoBackslashEscapes == 0 {
|
||||
buf = escapeBytesBackslash(buf, v)
|
||||
} else {
|
||||
buf = escapeBytesQuotes(buf, v)
|
||||
}
|
||||
buf = append(buf, '\'')
|
||||
case []byte:
|
||||
if v == nil {
|
||||
buf = append(buf, "NULL"...)
|
||||
@ -306,7 +295,7 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {
|
||||
if mc.closed.IsSet() {
|
||||
if mc.closed.Load() {
|
||||
errLog.Print(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
@ -367,7 +356,7 @@ func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, erro
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) {
|
||||
if mc.closed.IsSet() {
|
||||
if mc.closed.Load() {
|
||||
errLog.Print(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
@ -461,7 +450,7 @@ func (mc *mysqlConn) finish() {
|
||||
|
||||
// Ping implements driver.Pinger interface
|
||||
func (mc *mysqlConn) Ping(ctx context.Context) (err error) {
|
||||
if mc.closed.IsSet() {
|
||||
if mc.closed.Load() {
|
||||
errLog.Print(ErrInvalidConn)
|
||||
return driver.ErrBadConn
|
||||
}
|
||||
@ -480,6 +469,10 @@ func (mc *mysqlConn) Ping(ctx context.Context) (err error) {
|
||||
|
||||
// BeginTx implements driver.ConnBeginTx interface
|
||||
func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
|
||||
if mc.closed.Load() {
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
|
||||
if err := mc.watchCancel(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -643,9 +636,15 @@ func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) {
|
||||
// ResetSession implements driver.SessionResetter.
|
||||
// (From Go 1.10)
|
||||
func (mc *mysqlConn) ResetSession(ctx context.Context) error {
|
||||
if mc.closed.IsSet() {
|
||||
if mc.closed.Load() {
|
||||
return driver.ErrBadConn
|
||||
}
|
||||
mc.reset = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValid implements driver.Validator interface
|
||||
// (From Go 1.15)
|
||||
func (mc *mysqlConn) IsValid() bool {
|
||||
return !mc.closed.Load()
|
||||
}
|
||||
|
2
vendor/github.com/go-sql-driver/mysql/const.go
generated
vendored
2
vendor/github.com/go-sql-driver/mysql/const.go
generated
vendored
@ -10,7 +10,7 @@ package mysql
|
||||
|
||||
const (
|
||||
defaultAuthPlugin = "mysql_native_password"
|
||||
defaultMaxAllowedPacket = 4 << 20 // 4 MiB
|
||||
defaultMaxAllowedPacket = 64 << 20 // 64 MiB. See https://github.com/go-sql-driver/mysql/issues/1355
|
||||
minProtocolVersion = 10
|
||||
maxPacketSize = 1<<24 - 1
|
||||
timeFormat = "2006-01-02 15:04:05.999999"
|
||||
|
6
vendor/github.com/go-sql-driver/mysql/driver.go
generated
vendored
6
vendor/github.com/go-sql-driver/mysql/driver.go
generated
vendored
@ -8,10 +8,10 @@
|
||||
//
|
||||
// The driver should be used via the database/sql package:
|
||||
//
|
||||
// import "database/sql"
|
||||
// import _ "github.com/go-sql-driver/mysql"
|
||||
// import "database/sql"
|
||||
// import _ "github.com/go-sql-driver/mysql"
|
||||
//
|
||||
// db, err := sql.Open("mysql", "user:password@/dbname")
|
||||
// db, err := sql.Open("mysql", "user:password@/dbname")
|
||||
//
|
||||
// See https://github.com/go-sql-driver/mysql#usage for details
|
||||
package mysql
|
||||
|
75
vendor/github.com/go-sql-driver/mysql/dsn.go
generated
vendored
75
vendor/github.com/go-sql-driver/mysql/dsn.go
generated
vendored
@ -46,22 +46,23 @@ type Config struct {
|
||||
ServerPubKey string // Server public key name
|
||||
pubKey *rsa.PublicKey // Server public key
|
||||
TLSConfig string // TLS configuration name
|
||||
tls *tls.Config // TLS configuration
|
||||
TLS *tls.Config // TLS configuration, its priority is higher than TLSConfig
|
||||
Timeout time.Duration // Dial timeout
|
||||
ReadTimeout time.Duration // I/O read timeout
|
||||
WriteTimeout time.Duration // I/O write timeout
|
||||
|
||||
AllowAllFiles bool // Allow all files to be used with LOAD DATA LOCAL INFILE
|
||||
AllowCleartextPasswords bool // Allows the cleartext client side plugin
|
||||
AllowNativePasswords bool // Allows the native password authentication method
|
||||
AllowOldPasswords bool // Allows the old insecure password method
|
||||
CheckConnLiveness bool // Check connections for liveness before using them
|
||||
ClientFoundRows bool // Return number of matching rows instead of rows changed
|
||||
ColumnsWithAlias bool // Prepend table alias to column names
|
||||
InterpolateParams bool // Interpolate placeholders into query string
|
||||
MultiStatements bool // Allow multiple statements in one query
|
||||
ParseTime bool // Parse time values to time.Time
|
||||
RejectReadOnly bool // Reject read-only connections
|
||||
AllowAllFiles bool // Allow all files to be used with LOAD DATA LOCAL INFILE
|
||||
AllowCleartextPasswords bool // Allows the cleartext client side plugin
|
||||
AllowFallbackToPlaintext bool // Allows fallback to unencrypted connection if server does not support TLS
|
||||
AllowNativePasswords bool // Allows the native password authentication method
|
||||
AllowOldPasswords bool // Allows the old insecure password method
|
||||
CheckConnLiveness bool // Check connections for liveness before using them
|
||||
ClientFoundRows bool // Return number of matching rows instead of rows changed
|
||||
ColumnsWithAlias bool // Prepend table alias to column names
|
||||
InterpolateParams bool // Interpolate placeholders into query string
|
||||
MultiStatements bool // Allow multiple statements in one query
|
||||
ParseTime bool // Parse time values to time.Time
|
||||
RejectReadOnly bool // Reject read-only connections
|
||||
}
|
||||
|
||||
// NewConfig creates a new Config and sets default values.
|
||||
@ -77,8 +78,8 @@ func NewConfig() *Config {
|
||||
|
||||
func (cfg *Config) Clone() *Config {
|
||||
cp := *cfg
|
||||
if cp.tls != nil {
|
||||
cp.tls = cfg.tls.Clone()
|
||||
if cp.TLS != nil {
|
||||
cp.TLS = cfg.TLS.Clone()
|
||||
}
|
||||
if len(cp.Params) > 0 {
|
||||
cp.Params = make(map[string]string, len(cfg.Params))
|
||||
@ -119,24 +120,29 @@ func (cfg *Config) normalize() error {
|
||||
cfg.Addr = ensureHavePort(cfg.Addr)
|
||||
}
|
||||
|
||||
switch cfg.TLSConfig {
|
||||
case "false", "":
|
||||
// don't set anything
|
||||
case "true":
|
||||
cfg.tls = &tls.Config{}
|
||||
case "skip-verify", "preferred":
|
||||
cfg.tls = &tls.Config{InsecureSkipVerify: true}
|
||||
default:
|
||||
cfg.tls = getTLSConfigClone(cfg.TLSConfig)
|
||||
if cfg.tls == nil {
|
||||
return errors.New("invalid value / unknown config name: " + cfg.TLSConfig)
|
||||
if cfg.TLS == nil {
|
||||
switch cfg.TLSConfig {
|
||||
case "false", "":
|
||||
// don't set anything
|
||||
case "true":
|
||||
cfg.TLS = &tls.Config{}
|
||||
case "skip-verify":
|
||||
cfg.TLS = &tls.Config{InsecureSkipVerify: true}
|
||||
case "preferred":
|
||||
cfg.TLS = &tls.Config{InsecureSkipVerify: true}
|
||||
cfg.AllowFallbackToPlaintext = true
|
||||
default:
|
||||
cfg.TLS = getTLSConfigClone(cfg.TLSConfig)
|
||||
if cfg.TLS == nil {
|
||||
return errors.New("invalid value / unknown config name: " + cfg.TLSConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.tls != nil && cfg.tls.ServerName == "" && !cfg.tls.InsecureSkipVerify {
|
||||
if cfg.TLS != nil && cfg.TLS.ServerName == "" && !cfg.TLS.InsecureSkipVerify {
|
||||
host, _, err := net.SplitHostPort(cfg.Addr)
|
||||
if err == nil {
|
||||
cfg.tls.ServerName = host
|
||||
cfg.TLS.ServerName = host
|
||||
}
|
||||
}
|
||||
|
||||
@ -204,6 +210,10 @@ func (cfg *Config) FormatDSN() string {
|
||||
writeDSNParam(&buf, &hasParam, "allowCleartextPasswords", "true")
|
||||
}
|
||||
|
||||
if cfg.AllowFallbackToPlaintext {
|
||||
writeDSNParam(&buf, &hasParam, "allowFallbackToPlaintext", "true")
|
||||
}
|
||||
|
||||
if !cfg.AllowNativePasswords {
|
||||
writeDSNParam(&buf, &hasParam, "allowNativePasswords", "false")
|
||||
}
|
||||
@ -375,7 +385,7 @@ func parseDSNParams(cfg *Config, params string) (err error) {
|
||||
|
||||
// cfg params
|
||||
switch value := param[1]; param[0] {
|
||||
// Disable INFILE whitelist / enable all files
|
||||
// Disable INFILE allowlist / enable all files
|
||||
case "allowAllFiles":
|
||||
var isBool bool
|
||||
cfg.AllowAllFiles, isBool = readBool(value)
|
||||
@ -391,6 +401,14 @@ func parseDSNParams(cfg *Config, params string) (err error) {
|
||||
return errors.New("invalid bool value: " + value)
|
||||
}
|
||||
|
||||
// Allow fallback to unencrypted connection if server does not support TLS
|
||||
case "allowFallbackToPlaintext":
|
||||
var isBool bool
|
||||
cfg.AllowFallbackToPlaintext, isBool = readBool(value)
|
||||
if !isBool {
|
||||
return errors.New("invalid bool value: " + value)
|
||||
}
|
||||
|
||||
// Use native password authentication
|
||||
case "allowNativePasswords":
|
||||
var isBool bool
|
||||
@ -426,7 +444,6 @@ func parseDSNParams(cfg *Config, params string) (err error) {
|
||||
// Collation
|
||||
case "collation":
|
||||
cfg.Collation = value
|
||||
break
|
||||
|
||||
case "columnsWithAlias":
|
||||
var isBool bool
|
||||
|
18
vendor/github.com/go-sql-driver/mysql/errors.go
generated
vendored
18
vendor/github.com/go-sql-driver/mysql/errors.go
generated
vendored
@ -27,7 +27,7 @@ var (
|
||||
ErrOldProtocol = errors.New("MySQL server does not support required protocol 41+")
|
||||
ErrPktSync = errors.New("commands out of sync. You can't run this command now")
|
||||
ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?")
|
||||
ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server")
|
||||
ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the `Config.MaxAllowedPacket`")
|
||||
ErrBusyBuffer = errors.New("busy buffer")
|
||||
|
||||
// errBadConnNoWrite is used for connection errors where nothing was sent to the database yet.
|
||||
@ -56,10 +56,22 @@ func SetLogger(logger Logger) error {
|
||||
|
||||
// MySQLError is an error type which represents a single MySQL error
|
||||
type MySQLError struct {
|
||||
Number uint16
|
||||
Message string
|
||||
Number uint16
|
||||
SQLState [5]byte
|
||||
Message string
|
||||
}
|
||||
|
||||
func (me *MySQLError) Error() string {
|
||||
if me.SQLState != [5]byte{} {
|
||||
return fmt.Sprintf("Error %d (%s): %s", me.Number, me.SQLState, me.Message)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Error %d: %s", me.Number, me.Message)
|
||||
}
|
||||
|
||||
func (me *MySQLError) Is(err error) bool {
|
||||
if merr, ok := err.(*MySQLError); ok {
|
||||
return merr.Number == me.Number
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
14
vendor/github.com/go-sql-driver/mysql/fields.go
generated
vendored
14
vendor/github.com/go-sql-driver/mysql/fields.go
generated
vendored
@ -41,6 +41,9 @@ func (mf *mysqlField) typeDatabaseName() string {
|
||||
case fieldTypeJSON:
|
||||
return "JSON"
|
||||
case fieldTypeLong:
|
||||
if mf.flags&flagUnsigned != 0 {
|
||||
return "UNSIGNED INT"
|
||||
}
|
||||
return "INT"
|
||||
case fieldTypeLongBLOB:
|
||||
if mf.charSet != collations[binaryCollation] {
|
||||
@ -48,6 +51,9 @@ func (mf *mysqlField) typeDatabaseName() string {
|
||||
}
|
||||
return "LONGBLOB"
|
||||
case fieldTypeLongLong:
|
||||
if mf.flags&flagUnsigned != 0 {
|
||||
return "UNSIGNED BIGINT"
|
||||
}
|
||||
return "BIGINT"
|
||||
case fieldTypeMediumBLOB:
|
||||
if mf.charSet != collations[binaryCollation] {
|
||||
@ -63,6 +69,9 @@ func (mf *mysqlField) typeDatabaseName() string {
|
||||
case fieldTypeSet:
|
||||
return "SET"
|
||||
case fieldTypeShort:
|
||||
if mf.flags&flagUnsigned != 0 {
|
||||
return "UNSIGNED SMALLINT"
|
||||
}
|
||||
return "SMALLINT"
|
||||
case fieldTypeString:
|
||||
if mf.charSet == collations[binaryCollation] {
|
||||
@ -74,6 +83,9 @@ func (mf *mysqlField) typeDatabaseName() string {
|
||||
case fieldTypeTimestamp:
|
||||
return "TIMESTAMP"
|
||||
case fieldTypeTiny:
|
||||
if mf.flags&flagUnsigned != 0 {
|
||||
return "UNSIGNED TINYINT"
|
||||
}
|
||||
return "TINYINT"
|
||||
case fieldTypeTinyBLOB:
|
||||
if mf.charSet != collations[binaryCollation] {
|
||||
@ -106,7 +118,7 @@ var (
|
||||
scanTypeInt64 = reflect.TypeOf(int64(0))
|
||||
scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{})
|
||||
scanTypeNullInt = reflect.TypeOf(sql.NullInt64{})
|
||||
scanTypeNullTime = reflect.TypeOf(NullTime{})
|
||||
scanTypeNullTime = reflect.TypeOf(sql.NullTime{})
|
||||
scanTypeUint8 = reflect.TypeOf(uint8(0))
|
||||
scanTypeUint16 = reflect.TypeOf(uint16(0))
|
||||
scanTypeUint32 = reflect.TypeOf(uint32(0))
|
||||
|
25
vendor/github.com/go-sql-driver/mysql/fuzz.go
generated
vendored
Normal file
25
vendor/github.com/go-sql-driver/mysql/fuzz.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package.
|
||||
//
|
||||
// Copyright 2020 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
//go:build gofuzz
|
||||
// +build gofuzz
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
func Fuzz(data []byte) int {
|
||||
db, err := sql.Open("mysql", string(data))
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
db.Close()
|
||||
return 1
|
||||
}
|
3
vendor/github.com/go-sql-driver/mysql/go.mod
generated
vendored
3
vendor/github.com/go-sql-driver/mysql/go.mod
generated
vendored
@ -1,3 +0,0 @@
|
||||
module github.com/go-sql-driver/mysql
|
||||
|
||||
go 1.10
|
36
vendor/github.com/go-sql-driver/mysql/infile.go
generated
vendored
36
vendor/github.com/go-sql-driver/mysql/infile.go
generated
vendored
@ -23,17 +23,16 @@ var (
|
||||
readerRegisterLock sync.RWMutex
|
||||
)
|
||||
|
||||
// RegisterLocalFile adds the given file to the file whitelist,
|
||||
// RegisterLocalFile adds the given file to the file allowlist,
|
||||
// so that it can be used by "LOAD DATA LOCAL INFILE <filepath>".
|
||||
// Alternatively you can allow the use of all local files with
|
||||
// the DSN parameter 'allowAllFiles=true'
|
||||
//
|
||||
// filePath := "/home/gopher/data.csv"
|
||||
// mysql.RegisterLocalFile(filePath)
|
||||
// err := db.Exec("LOAD DATA LOCAL INFILE '" + filePath + "' INTO TABLE foo")
|
||||
// if err != nil {
|
||||
// ...
|
||||
//
|
||||
// filePath := "/home/gopher/data.csv"
|
||||
// mysql.RegisterLocalFile(filePath)
|
||||
// err := db.Exec("LOAD DATA LOCAL INFILE '" + filePath + "' INTO TABLE foo")
|
||||
// if err != nil {
|
||||
// ...
|
||||
func RegisterLocalFile(filePath string) {
|
||||
fileRegisterLock.Lock()
|
||||
// lazy map init
|
||||
@ -45,7 +44,7 @@ func RegisterLocalFile(filePath string) {
|
||||
fileRegisterLock.Unlock()
|
||||
}
|
||||
|
||||
// DeregisterLocalFile removes the given filepath from the whitelist.
|
||||
// DeregisterLocalFile removes the given filepath from the allowlist.
|
||||
func DeregisterLocalFile(filePath string) {
|
||||
fileRegisterLock.Lock()
|
||||
delete(fileRegister, strings.Trim(filePath, `"`))
|
||||
@ -58,15 +57,14 @@ func DeregisterLocalFile(filePath string) {
|
||||
// If the handler returns a io.ReadCloser Close() is called when the
|
||||
// request is finished.
|
||||
//
|
||||
// mysql.RegisterReaderHandler("data", func() io.Reader {
|
||||
// var csvReader io.Reader // Some Reader that returns CSV data
|
||||
// ... // Open Reader here
|
||||
// return csvReader
|
||||
// })
|
||||
// err := db.Exec("LOAD DATA LOCAL INFILE 'Reader::data' INTO TABLE foo")
|
||||
// if err != nil {
|
||||
// ...
|
||||
//
|
||||
// mysql.RegisterReaderHandler("data", func() io.Reader {
|
||||
// var csvReader io.Reader // Some Reader that returns CSV data
|
||||
// ... // Open Reader here
|
||||
// return csvReader
|
||||
// })
|
||||
// err := db.Exec("LOAD DATA LOCAL INFILE 'Reader::data' INTO TABLE foo")
|
||||
// if err != nil {
|
||||
// ...
|
||||
func RegisterReaderHandler(name string, handler func() io.Reader) {
|
||||
readerRegisterLock.Lock()
|
||||
// lazy map init
|
||||
@ -93,10 +91,12 @@ func deferredClose(err *error, closer io.Closer) {
|
||||
}
|
||||
}
|
||||
|
||||
const defaultPacketSize = 16 * 1024 // 16KB is small enough for disk readahead and large enough for TCP
|
||||
|
||||
func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
|
||||
var rdr io.Reader
|
||||
var data []byte
|
||||
packetSize := 16 * 1024 // 16KB is small enough for disk readahead and large enough for TCP
|
||||
packetSize := defaultPacketSize
|
||||
if mc.maxWriteSize < packetSize {
|
||||
packetSize = mc.maxWriteSize
|
||||
}
|
||||
|
25
vendor/github.com/go-sql-driver/mysql/nulltime.go
generated
vendored
25
vendor/github.com/go-sql-driver/mysql/nulltime.go
generated
vendored
@ -9,11 +9,32 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NullTime represents a time.Time that may be NULL.
|
||||
// NullTime implements the Scanner interface so
|
||||
// it can be used as a scan destination:
|
||||
//
|
||||
// var nt NullTime
|
||||
// err := db.QueryRow("SELECT time FROM foo WHERE id=?", id).Scan(&nt)
|
||||
// ...
|
||||
// if nt.Valid {
|
||||
// // use nt.Time
|
||||
// } else {
|
||||
// // NULL value
|
||||
// }
|
||||
//
|
||||
// # This NullTime implementation is not driver-specific
|
||||
//
|
||||
// Deprecated: NullTime doesn't honor the loc DSN parameter.
|
||||
// NullTime.Scan interprets a time as UTC, not the loc DSN parameter.
|
||||
// Use sql.NullTime instead.
|
||||
type NullTime sql.NullTime
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
// The value type must be time.Time or string / []byte (formatted time-string),
|
||||
// otherwise Scan fails.
|
||||
@ -28,11 +49,11 @@ func (nt *NullTime) Scan(value interface{}) (err error) {
|
||||
nt.Time, nt.Valid = v, true
|
||||
return
|
||||
case []byte:
|
||||
nt.Time, err = parseDateTime(string(v), time.UTC)
|
||||
nt.Time, err = parseDateTime(v, time.UTC)
|
||||
nt.Valid = (err == nil)
|
||||
return
|
||||
case string:
|
||||
nt.Time, err = parseDateTime(v, time.UTC)
|
||||
nt.Time, err = parseDateTime([]byte(v), time.UTC)
|
||||
nt.Valid = (err == nil)
|
||||
return
|
||||
}
|
||||
|
31
vendor/github.com/go-sql-driver/mysql/nulltime_go113.go
generated
vendored
31
vendor/github.com/go-sql-driver/mysql/nulltime_go113.go
generated
vendored
@ -1,31 +0,0 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// +build go1.13
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
// NullTime represents a time.Time that may be NULL.
|
||||
// NullTime implements the Scanner interface so
|
||||
// it can be used as a scan destination:
|
||||
//
|
||||
// var nt NullTime
|
||||
// err := db.QueryRow("SELECT time FROM foo WHERE id=?", id).Scan(&nt)
|
||||
// ...
|
||||
// if nt.Valid {
|
||||
// // use nt.Time
|
||||
// } else {
|
||||
// // NULL value
|
||||
// }
|
||||
//
|
||||
// This NullTime implementation is not driver-specific
|
||||
type NullTime sql.NullTime
|
34
vendor/github.com/go-sql-driver/mysql/nulltime_legacy.go
generated
vendored
34
vendor/github.com/go-sql-driver/mysql/nulltime_legacy.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// +build !go1.13
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// NullTime represents a time.Time that may be NULL.
|
||||
// NullTime implements the Scanner interface so
|
||||
// it can be used as a scan destination:
|
||||
//
|
||||
// var nt NullTime
|
||||
// err := db.QueryRow("SELECT time FROM foo WHERE id=?", id).Scan(&nt)
|
||||
// ...
|
||||
// if nt.Valid {
|
||||
// // use nt.Time
|
||||
// } else {
|
||||
// // NULL value
|
||||
// }
|
||||
//
|
||||
// This NullTime implementation is not driver-specific
|
||||
type NullTime struct {
|
||||
Time time.Time
|
||||
Valid bool // Valid is true if Time is not NULL
|
||||
}
|
111
vendor/github.com/go-sql-driver/mysql/packets.go
generated
vendored
111
vendor/github.com/go-sql-driver/mysql/packets.go
generated
vendored
@ -13,6 +13,7 @@ import (
|
||||
"crypto/tls"
|
||||
"database/sql/driver"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -109,14 +110,13 @@ func (mc *mysqlConn) writePacket(data []byte) error {
|
||||
conn = mc.rawConn
|
||||
}
|
||||
var err error
|
||||
// If this connection has a ReadTimeout which we've been setting on
|
||||
// reads, reset it to its default value before we attempt a non-blocking
|
||||
// read, otherwise the scheduler will just time us out before we can read
|
||||
if mc.cfg.ReadTimeout != 0 {
|
||||
err = conn.SetReadDeadline(time.Time{})
|
||||
}
|
||||
if err == nil && mc.cfg.CheckConnLiveness {
|
||||
err = connCheck(conn)
|
||||
if mc.cfg.CheckConnLiveness {
|
||||
if mc.cfg.ReadTimeout != 0 {
|
||||
err = conn.SetReadDeadline(time.Now().Add(mc.cfg.ReadTimeout))
|
||||
}
|
||||
if err == nil {
|
||||
err = connCheck(conn)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
errLog.Print("closing bad idle connection: ", err)
|
||||
@ -222,9 +222,9 @@ func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err erro
|
||||
if mc.flags&clientProtocol41 == 0 {
|
||||
return nil, "", ErrOldProtocol
|
||||
}
|
||||
if mc.flags&clientSSL == 0 && mc.cfg.tls != nil {
|
||||
if mc.cfg.TLSConfig == "preferred" {
|
||||
mc.cfg.tls = nil
|
||||
if mc.flags&clientSSL == 0 && mc.cfg.TLS != nil {
|
||||
if mc.cfg.AllowFallbackToPlaintext {
|
||||
mc.cfg.TLS = nil
|
||||
} else {
|
||||
return nil, "", ErrNoTLS
|
||||
}
|
||||
@ -292,7 +292,7 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
|
||||
}
|
||||
|
||||
// To enable TLS / SSL
|
||||
if mc.cfg.tls != nil {
|
||||
if mc.cfg.TLS != nil {
|
||||
clientFlags |= clientSSL
|
||||
}
|
||||
|
||||
@ -348,16 +348,22 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
|
||||
return errors.New("unknown collation")
|
||||
}
|
||||
|
||||
// Filler [23 bytes] (all 0x00)
|
||||
pos := 13
|
||||
for ; pos < 13+23; pos++ {
|
||||
data[pos] = 0
|
||||
}
|
||||
|
||||
// SSL Connection Request Packet
|
||||
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::SSLRequest
|
||||
if mc.cfg.tls != nil {
|
||||
if mc.cfg.TLS != nil {
|
||||
// Send TLS / SSL request packet
|
||||
if err := mc.writePacket(data[:(4+4+1+23)+4]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Switch to TLS
|
||||
tlsConn := tls.Client(mc.netConn, mc.cfg.tls)
|
||||
tlsConn := tls.Client(mc.netConn, mc.cfg.TLS)
|
||||
if err := tlsConn.Handshake(); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -366,12 +372,6 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
|
||||
mc.buf.nc = tlsConn
|
||||
}
|
||||
|
||||
// Filler [23 bytes] (all 0x00)
|
||||
pos := 13
|
||||
for ; pos < 13+23; pos++ {
|
||||
data[pos] = 0
|
||||
}
|
||||
|
||||
// User [null terminated string]
|
||||
if len(mc.cfg.User) > 0 {
|
||||
pos += copy(data[pos:], mc.cfg.User)
|
||||
@ -587,19 +587,20 @@ func (mc *mysqlConn) handleErrorPacket(data []byte) error {
|
||||
return driver.ErrBadConn
|
||||
}
|
||||
|
||||
me := &MySQLError{Number: errno}
|
||||
|
||||
pos := 3
|
||||
|
||||
// SQL State [optional: # + 5bytes string]
|
||||
if data[3] == 0x23 {
|
||||
//sqlstate := string(data[4 : 4+5])
|
||||
copy(me.SQLState[:], data[4:4+5])
|
||||
pos = 9
|
||||
}
|
||||
|
||||
// Error Message [string]
|
||||
return &MySQLError{
|
||||
Number: errno,
|
||||
Message: string(data[pos:]),
|
||||
}
|
||||
me.Message = string(data[pos:])
|
||||
|
||||
return me
|
||||
}
|
||||
|
||||
func readStatus(b []byte) statusFlag {
|
||||
@ -760,40 +761,40 @@ func (rows *textRows) readRow(dest []driver.Value) error {
|
||||
}
|
||||
|
||||
// RowSet Packet
|
||||
var n int
|
||||
var isNull bool
|
||||
pos := 0
|
||||
var (
|
||||
n int
|
||||
isNull bool
|
||||
pos int = 0
|
||||
)
|
||||
|
||||
for i := range dest {
|
||||
// Read bytes and convert to string
|
||||
dest[i], isNull, n, err = readLengthEncodedString(data[pos:])
|
||||
pos += n
|
||||
if err == nil {
|
||||
if !isNull {
|
||||
if !mc.parseTime {
|
||||
continue
|
||||
} else {
|
||||
switch rows.rs.columns[i].fieldType {
|
||||
case fieldTypeTimestamp, fieldTypeDateTime,
|
||||
fieldTypeDate, fieldTypeNewDate:
|
||||
dest[i], err = parseDateTime(
|
||||
string(dest[i].([]byte)),
|
||||
mc.cfg.Loc,
|
||||
)
|
||||
if err == nil {
|
||||
continue
|
||||
}
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
dest[i] = nil
|
||||
continue
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if isNull {
|
||||
dest[i] = nil
|
||||
continue
|
||||
}
|
||||
|
||||
if !mc.parseTime {
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse time field
|
||||
switch rows.rs.columns[i].fieldType {
|
||||
case fieldTypeTimestamp,
|
||||
fieldTypeDateTime,
|
||||
fieldTypeDate,
|
||||
fieldTypeNewDate:
|
||||
if dest[i], err = parseDateTime(dest[i].([]byte), mc.cfg.Loc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err // err != nil
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -1003,6 +1004,9 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
||||
continue
|
||||
}
|
||||
|
||||
if v, ok := arg.(json.RawMessage); ok {
|
||||
arg = []byte(v)
|
||||
}
|
||||
// cache types and values
|
||||
switch v := arg.(type) {
|
||||
case int64:
|
||||
@ -1112,7 +1116,10 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
||||
if v.IsZero() {
|
||||
b = append(b, "0000-00-00"...)
|
||||
} else {
|
||||
b = v.In(mc.cfg.Loc).AppendFormat(b, timeFormat)
|
||||
b, err = appendDateTime(b, v.In(mc.cfg.Loc))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
paramValues = appendLengthEncodedInteger(paramValues,
|
||||
|
36
vendor/github.com/go-sql-driver/mysql/statement.go
generated
vendored
36
vendor/github.com/go-sql-driver/mysql/statement.go
generated
vendored
@ -10,6 +10,7 @@ package mysql
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
@ -22,7 +23,7 @@ type mysqlStmt struct {
|
||||
}
|
||||
|
||||
func (stmt *mysqlStmt) Close() error {
|
||||
if stmt.mc == nil || stmt.mc.closed.IsSet() {
|
||||
if stmt.mc == nil || stmt.mc.closed.Load() {
|
||||
// driver.Stmt.Close can be called more than once, thus this function
|
||||
// has to be idempotent.
|
||||
// See also Issue #450 and golang/go#16019.
|
||||
@ -43,8 +44,13 @@ func (stmt *mysqlStmt) ColumnConverter(idx int) driver.ValueConverter {
|
||||
return converter{}
|
||||
}
|
||||
|
||||
func (stmt *mysqlStmt) CheckNamedValue(nv *driver.NamedValue) (err error) {
|
||||
nv.Value, err = converter{}.ConvertValue(nv.Value)
|
||||
return
|
||||
}
|
||||
|
||||
func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
|
||||
if stmt.mc.closed.IsSet() {
|
||||
if stmt.mc.closed.Load() {
|
||||
errLog.Print(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
@ -92,7 +98,7 @@ func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
|
||||
}
|
||||
|
||||
func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {
|
||||
if stmt.mc.closed.IsSet() {
|
||||
if stmt.mc.closed.Load() {
|
||||
errLog.Print(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
@ -129,6 +135,8 @@ func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {
|
||||
return rows, err
|
||||
}
|
||||
|
||||
var jsonType = reflect.TypeOf(json.RawMessage{})
|
||||
|
||||
type converter struct{}
|
||||
|
||||
// ConvertValue mirrors the reference/default converter in database/sql/driver
|
||||
@ -146,12 +154,17 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !driver.IsValue(sv) {
|
||||
return nil, fmt.Errorf("non-Value type %T returned from Value", sv)
|
||||
if driver.IsValue(sv) {
|
||||
return sv, nil
|
||||
}
|
||||
return sv, nil
|
||||
// A value returned from the Valuer interface can be "a type handled by
|
||||
// a database driver's NamedValueChecker interface" so we should accept
|
||||
// uint64 here as well.
|
||||
if u, ok := sv.(uint64); ok {
|
||||
return u, nil
|
||||
}
|
||||
return nil, fmt.Errorf("non-Value type %T returned from Value", sv)
|
||||
}
|
||||
|
||||
rv := reflect.ValueOf(v)
|
||||
switch rv.Kind() {
|
||||
case reflect.Ptr:
|
||||
@ -170,11 +183,14 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
|
||||
case reflect.Bool:
|
||||
return rv.Bool(), nil
|
||||
case reflect.Slice:
|
||||
ek := rv.Type().Elem().Kind()
|
||||
if ek == reflect.Uint8 {
|
||||
switch t := rv.Type(); {
|
||||
case t == jsonType:
|
||||
return v, nil
|
||||
case t.Elem().Kind() == reflect.Uint8:
|
||||
return rv.Bytes(), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, t.Elem().Kind())
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek)
|
||||
case reflect.String:
|
||||
return rv.String(), nil
|
||||
}
|
||||
|
4
vendor/github.com/go-sql-driver/mysql/transaction.go
generated
vendored
4
vendor/github.com/go-sql-driver/mysql/transaction.go
generated
vendored
@ -13,7 +13,7 @@ type mysqlTx struct {
|
||||
}
|
||||
|
||||
func (tx *mysqlTx) Commit() (err error) {
|
||||
if tx.mc == nil || tx.mc.closed.IsSet() {
|
||||
if tx.mc == nil || tx.mc.closed.Load() {
|
||||
return ErrInvalidConn
|
||||
}
|
||||
err = tx.mc.exec("COMMIT")
|
||||
@ -22,7 +22,7 @@ func (tx *mysqlTx) Commit() (err error) {
|
||||
}
|
||||
|
||||
func (tx *mysqlTx) Rollback() (err error) {
|
||||
if tx.mc == nil || tx.mc.closed.IsSet() {
|
||||
if tx.mc == nil || tx.mc.closed.Load() {
|
||||
return ErrInvalidConn
|
||||
}
|
||||
err = tx.mc.exec("ROLLBACK")
|
||||
|
295
vendor/github.com/go-sql-driver/mysql/utils.go
generated
vendored
295
vendor/github.com/go-sql-driver/mysql/utils.go
generated
vendored
@ -35,26 +35,25 @@ var (
|
||||
// Note: The provided tls.Config is exclusively owned by the driver after
|
||||
// registering it.
|
||||
//
|
||||
// rootCertPool := x509.NewCertPool()
|
||||
// pem, err := ioutil.ReadFile("/path/ca-cert.pem")
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
|
||||
// log.Fatal("Failed to append PEM.")
|
||||
// }
|
||||
// clientCert := make([]tls.Certificate, 0, 1)
|
||||
// certs, err := tls.LoadX509KeyPair("/path/client-cert.pem", "/path/client-key.pem")
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// clientCert = append(clientCert, certs)
|
||||
// mysql.RegisterTLSConfig("custom", &tls.Config{
|
||||
// RootCAs: rootCertPool,
|
||||
// Certificates: clientCert,
|
||||
// })
|
||||
// db, err := sql.Open("mysql", "user@tcp(localhost:3306)/test?tls=custom")
|
||||
//
|
||||
// rootCertPool := x509.NewCertPool()
|
||||
// pem, err := ioutil.ReadFile("/path/ca-cert.pem")
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
|
||||
// log.Fatal("Failed to append PEM.")
|
||||
// }
|
||||
// clientCert := make([]tls.Certificate, 0, 1)
|
||||
// certs, err := tls.LoadX509KeyPair("/path/client-cert.pem", "/path/client-key.pem")
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// clientCert = append(clientCert, certs)
|
||||
// mysql.RegisterTLSConfig("custom", &tls.Config{
|
||||
// RootCAs: rootCertPool,
|
||||
// Certificates: clientCert,
|
||||
// })
|
||||
// db, err := sql.Open("mysql", "user@tcp(localhost:3306)/test?tls=custom")
|
||||
func RegisterTLSConfig(key string, config *tls.Config) error {
|
||||
if _, isBool := readBool(key); isBool || strings.ToLower(key) == "skip-verify" || strings.ToLower(key) == "preferred" {
|
||||
return fmt.Errorf("key '%s' is reserved", key)
|
||||
@ -106,27 +105,126 @@ func readBool(input string) (value bool, valid bool) {
|
||||
* Time related utils *
|
||||
******************************************************************************/
|
||||
|
||||
func parseDateTime(str string, loc *time.Location) (t time.Time, err error) {
|
||||
base := "0000-00-00 00:00:00.0000000"
|
||||
switch len(str) {
|
||||
func parseDateTime(b []byte, loc *time.Location) (time.Time, error) {
|
||||
const base = "0000-00-00 00:00:00.000000"
|
||||
switch len(b) {
|
||||
case 10, 19, 21, 22, 23, 24, 25, 26: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM"
|
||||
if str == base[:len(str)] {
|
||||
return
|
||||
if string(b) == base[:len(b)] {
|
||||
return time.Time{}, nil
|
||||
}
|
||||
t, err = time.Parse(timeFormat[:len(str)], str)
|
||||
|
||||
year, err := parseByteYear(b)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
if b[4] != '-' {
|
||||
return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[4])
|
||||
}
|
||||
|
||||
m, err := parseByte2Digits(b[5], b[6])
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
month := time.Month(m)
|
||||
|
||||
if b[7] != '-' {
|
||||
return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[7])
|
||||
}
|
||||
|
||||
day, err := parseByte2Digits(b[8], b[9])
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
if len(b) == 10 {
|
||||
return time.Date(year, month, day, 0, 0, 0, 0, loc), nil
|
||||
}
|
||||
|
||||
if b[10] != ' ' {
|
||||
return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[10])
|
||||
}
|
||||
|
||||
hour, err := parseByte2Digits(b[11], b[12])
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
if b[13] != ':' {
|
||||
return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[13])
|
||||
}
|
||||
|
||||
min, err := parseByte2Digits(b[14], b[15])
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
if b[16] != ':' {
|
||||
return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[16])
|
||||
}
|
||||
|
||||
sec, err := parseByte2Digits(b[17], b[18])
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
if len(b) == 19 {
|
||||
return time.Date(year, month, day, hour, min, sec, 0, loc), nil
|
||||
}
|
||||
|
||||
if b[19] != '.' {
|
||||
return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[19])
|
||||
}
|
||||
nsec, err := parseByteNanoSec(b[20:])
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return time.Date(year, month, day, hour, min, sec, nsec, loc), nil
|
||||
default:
|
||||
err = fmt.Errorf("invalid time string: %s", str)
|
||||
return
|
||||
return time.Time{}, fmt.Errorf("invalid time bytes: %s", b)
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust location
|
||||
if err == nil && loc != time.UTC {
|
||||
y, mo, d := t.Date()
|
||||
h, mi, s := t.Clock()
|
||||
t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil
|
||||
func parseByteYear(b []byte) (int, error) {
|
||||
year, n := 0, 1000
|
||||
for i := 0; i < 4; i++ {
|
||||
v, err := bToi(b[i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
year += v * n
|
||||
n /= 10
|
||||
}
|
||||
return year, nil
|
||||
}
|
||||
|
||||
return
|
||||
func parseByte2Digits(b1, b2 byte) (int, error) {
|
||||
d1, err := bToi(b1)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
d2, err := bToi(b2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d1*10 + d2, nil
|
||||
}
|
||||
|
||||
func parseByteNanoSec(b []byte) (int, error) {
|
||||
ns, digit := 0, 100000 // max is 6-digits
|
||||
for i := 0; i < len(b); i++ {
|
||||
v, err := bToi(b[i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ns += v * digit
|
||||
digit /= 10
|
||||
}
|
||||
// nanoseconds has 10-digits. (needs to scale digits)
|
||||
// 10 - 6 = 4, so we have to multiple 1000.
|
||||
return ns * 1000, nil
|
||||
}
|
||||
|
||||
func bToi(b byte) (int, error) {
|
||||
if b < '0' || b > '9' {
|
||||
return 0, errors.New("not [0-9]")
|
||||
}
|
||||
return int(b - '0'), nil
|
||||
}
|
||||
|
||||
func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Value, error) {
|
||||
@ -167,6 +265,64 @@ func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Va
|
||||
return nil, fmt.Errorf("invalid DATETIME packet length %d", num)
|
||||
}
|
||||
|
||||
func appendDateTime(buf []byte, t time.Time) ([]byte, error) {
|
||||
year, month, day := t.Date()
|
||||
hour, min, sec := t.Clock()
|
||||
nsec := t.Nanosecond()
|
||||
|
||||
if year < 1 || year > 9999 {
|
||||
return buf, errors.New("year is not in the range [1, 9999]: " + strconv.Itoa(year)) // use errors.New instead of fmt.Errorf to avoid year escape to heap
|
||||
}
|
||||
year100 := year / 100
|
||||
year1 := year % 100
|
||||
|
||||
var localBuf [len("2006-01-02T15:04:05.999999999")]byte // does not escape
|
||||
localBuf[0], localBuf[1], localBuf[2], localBuf[3] = digits10[year100], digits01[year100], digits10[year1], digits01[year1]
|
||||
localBuf[4] = '-'
|
||||
localBuf[5], localBuf[6] = digits10[month], digits01[month]
|
||||
localBuf[7] = '-'
|
||||
localBuf[8], localBuf[9] = digits10[day], digits01[day]
|
||||
|
||||
if hour == 0 && min == 0 && sec == 0 && nsec == 0 {
|
||||
return append(buf, localBuf[:10]...), nil
|
||||
}
|
||||
|
||||
localBuf[10] = ' '
|
||||
localBuf[11], localBuf[12] = digits10[hour], digits01[hour]
|
||||
localBuf[13] = ':'
|
||||
localBuf[14], localBuf[15] = digits10[min], digits01[min]
|
||||
localBuf[16] = ':'
|
||||
localBuf[17], localBuf[18] = digits10[sec], digits01[sec]
|
||||
|
||||
if nsec == 0 {
|
||||
return append(buf, localBuf[:19]...), nil
|
||||
}
|
||||
nsec100000000 := nsec / 100000000
|
||||
nsec1000000 := (nsec / 1000000) % 100
|
||||
nsec10000 := (nsec / 10000) % 100
|
||||
nsec100 := (nsec / 100) % 100
|
||||
nsec1 := nsec % 100
|
||||
localBuf[19] = '.'
|
||||
|
||||
// milli second
|
||||
localBuf[20], localBuf[21], localBuf[22] =
|
||||
digits01[nsec100000000], digits10[nsec1000000], digits01[nsec1000000]
|
||||
// micro second
|
||||
localBuf[23], localBuf[24], localBuf[25] =
|
||||
digits10[nsec10000], digits01[nsec10000], digits10[nsec100]
|
||||
// nano second
|
||||
localBuf[26], localBuf[27], localBuf[28] =
|
||||
digits01[nsec100], digits10[nsec1], digits01[nsec1]
|
||||
|
||||
// trim trailing zeros
|
||||
n := len(localBuf)
|
||||
for n > 0 && localBuf[n-1] == '0' {
|
||||
n--
|
||||
}
|
||||
|
||||
return append(buf, localBuf[:n]...), nil
|
||||
}
|
||||
|
||||
// zeroDateTime is used in formatBinaryDateTime to avoid an allocation
|
||||
// if the DATE or DATETIME has the zero value.
|
||||
// It must never be changed.
|
||||
@ -375,7 +531,7 @@ func stringToInt(b []byte) int {
|
||||
return val
|
||||
}
|
||||
|
||||
// returns the string read as a bytes slice, wheter the value is NULL,
|
||||
// returns the string read as a bytes slice, whether the value is NULL,
|
||||
// the number of bytes read and an error, in case the string is longer than
|
||||
// the input slice
|
||||
func readLengthEncodedString(b []byte) ([]byte, bool, int, error) {
|
||||
@ -485,32 +641,32 @@ func escapeBytesBackslash(buf, v []byte) []byte {
|
||||
for _, c := range v {
|
||||
switch c {
|
||||
case '\x00':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = '0'
|
||||
buf[pos] = '\\'
|
||||
pos += 2
|
||||
case '\n':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = 'n'
|
||||
buf[pos] = '\\'
|
||||
pos += 2
|
||||
case '\r':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = 'r'
|
||||
buf[pos] = '\\'
|
||||
pos += 2
|
||||
case '\x1a':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = 'Z'
|
||||
buf[pos] = '\\'
|
||||
pos += 2
|
||||
case '\'':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = '\''
|
||||
buf[pos] = '\\'
|
||||
pos += 2
|
||||
case '"':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = '"'
|
||||
buf[pos] = '\\'
|
||||
pos += 2
|
||||
case '\\':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = '\\'
|
||||
buf[pos] = '\\'
|
||||
pos += 2
|
||||
default:
|
||||
buf[pos] = c
|
||||
@ -530,32 +686,32 @@ func escapeStringBackslash(buf []byte, v string) []byte {
|
||||
c := v[i]
|
||||
switch c {
|
||||
case '\x00':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = '0'
|
||||
buf[pos] = '\\'
|
||||
pos += 2
|
||||
case '\n':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = 'n'
|
||||
buf[pos] = '\\'
|
||||
pos += 2
|
||||
case '\r':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = 'r'
|
||||
buf[pos] = '\\'
|
||||
pos += 2
|
||||
case '\x1a':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = 'Z'
|
||||
buf[pos] = '\\'
|
||||
pos += 2
|
||||
case '\'':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = '\''
|
||||
buf[pos] = '\\'
|
||||
pos += 2
|
||||
case '"':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = '"'
|
||||
buf[pos] = '\\'
|
||||
pos += 2
|
||||
case '\\':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = '\\'
|
||||
buf[pos] = '\\'
|
||||
pos += 2
|
||||
default:
|
||||
buf[pos] = c
|
||||
@ -577,8 +733,8 @@ func escapeBytesQuotes(buf, v []byte) []byte {
|
||||
|
||||
for _, c := range v {
|
||||
if c == '\'' {
|
||||
buf[pos] = '\''
|
||||
buf[pos+1] = '\''
|
||||
buf[pos] = '\''
|
||||
pos += 2
|
||||
} else {
|
||||
buf[pos] = c
|
||||
@ -597,8 +753,8 @@ func escapeStringQuotes(buf []byte, v string) []byte {
|
||||
for i := 0; i < len(v); i++ {
|
||||
c := v[i]
|
||||
if c == '\'' {
|
||||
buf[pos] = '\''
|
||||
buf[pos+1] = '\''
|
||||
buf[pos] = '\''
|
||||
pos += 2
|
||||
} else {
|
||||
buf[pos] = c
|
||||
@ -623,39 +779,16 @@ type noCopy struct{}
|
||||
// Lock is a no-op used by -copylocks checker from `go vet`.
|
||||
func (*noCopy) Lock() {}
|
||||
|
||||
// atomicBool is a wrapper around uint32 for usage as a boolean value with
|
||||
// atomic access.
|
||||
type atomicBool struct {
|
||||
_noCopy noCopy
|
||||
value uint32
|
||||
}
|
||||
|
||||
// IsSet returns whether the current boolean value is true
|
||||
func (ab *atomicBool) IsSet() bool {
|
||||
return atomic.LoadUint32(&ab.value) > 0
|
||||
}
|
||||
|
||||
// Set sets the value of the bool regardless of the previous value
|
||||
func (ab *atomicBool) Set(value bool) {
|
||||
if value {
|
||||
atomic.StoreUint32(&ab.value, 1)
|
||||
} else {
|
||||
atomic.StoreUint32(&ab.value, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// TrySet sets the value of the bool and returns whether the value changed
|
||||
func (ab *atomicBool) TrySet(value bool) bool {
|
||||
if value {
|
||||
return atomic.SwapUint32(&ab.value, 1) == 0
|
||||
}
|
||||
return atomic.SwapUint32(&ab.value, 0) > 0
|
||||
}
|
||||
// Unlock is a no-op used by -copylocks checker from `go vet`.
|
||||
// noCopy should implement sync.Locker from Go 1.11
|
||||
// https://github.com/golang/go/commit/c2eba53e7f80df21d51285879d51ab81bcfbf6bc
|
||||
// https://github.com/golang/go/issues/26165
|
||||
func (*noCopy) Unlock() {}
|
||||
|
||||
// atomicError is a wrapper for atomically accessed error values
|
||||
type atomicError struct {
|
||||
_noCopy noCopy
|
||||
value atomic.Value
|
||||
_ noCopy
|
||||
value atomic.Value
|
||||
}
|
||||
|
||||
// Set sets the error value regardless of the previous value.
|
||||
|
40
vendor/github.com/jinzhu/gorm/README.md
generated
vendored
40
vendor/github.com/jinzhu/gorm/README.md
generated
vendored
@ -1,41 +1,5 @@
|
||||
# GORM
|
||||
|
||||
The fantastic ORM library for Golang, aims to be developer friendly.
|
||||
GORM V2 moved to https://github.com/go-gorm/gorm
|
||||
|
||||
[![go report card](https://goreportcard.com/badge/github.com/jinzhu/gorm "go report card")](https://goreportcard.com/report/github.com/jinzhu/gorm)
|
||||
[![wercker status](https://app.wercker.com/status/8596cace912c9947dd9c8542ecc8cb8b/s/master "wercker status")](https://app.wercker.com/project/byKey/8596cace912c9947dd9c8542ecc8cb8b)
|
||||
[![codecov](https://codecov.io/gh/jinzhu/gorm/branch/master/graph/badge.svg)](https://codecov.io/gh/jinzhu/gorm)
|
||||
[![Join the chat at https://gitter.im/jinzhu/gorm](https://img.shields.io/gitter/room/jinzhu/gorm.svg)](https://gitter.im/jinzhu/gorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[![Open Collective Backer](https://opencollective.com/gorm/tiers/backer/badge.svg?label=backer&color=brightgreen "Open Collective Backer")](https://opencollective.com/gorm)
|
||||
[![Open Collective Sponsor](https://opencollective.com/gorm/tiers/sponsor/badge.svg?label=sponsor&color=brightgreen "Open Collective Sponsor")](https://opencollective.com/gorm)
|
||||
[![MIT license](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)
|
||||
[![GoDoc](https://godoc.org/github.com/jinzhu/gorm?status.svg)](https://godoc.org/github.com/jinzhu/gorm)
|
||||
|
||||
## Overview
|
||||
|
||||
* Full-Featured ORM (almost)
|
||||
* Associations (Has One, Has Many, Belongs To, Many To Many, Polymorphism)
|
||||
* Hooks (Before/After Create/Save/Update/Delete/Find)
|
||||
* Preloading (eager loading)
|
||||
* Transactions
|
||||
* Composite Primary Key
|
||||
* SQL Builder
|
||||
* Auto Migrations
|
||||
* Logger
|
||||
* Extendable, write Plugins based on GORM callbacks
|
||||
* Every feature comes with tests
|
||||
* Developer Friendly
|
||||
|
||||
## Getting Started
|
||||
|
||||
* GORM Guides [https://gorm.io](https://gorm.io)
|
||||
|
||||
## Contributing
|
||||
|
||||
[You can help to deliver a better GORM, check out things you can do](https://gorm.io/contribute.html)
|
||||
|
||||
## License
|
||||
|
||||
© Jinzhu, 2013~time.Now
|
||||
|
||||
Released under the [MIT License](https://github.com/jinzhu/gorm/blob/master/License)
|
||||
GORM V1 Doc https://v1.gorm.io/
|
||||
|
15
vendor/github.com/jinzhu/gorm/go.mod
generated
vendored
15
vendor/github.com/jinzhu/gorm/go.mod
generated
vendored
@ -1,15 +0,0 @@
|
||||
module github.com/jinzhu/gorm
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5
|
||||
github.com/go-sql-driver/mysql v1.4.1
|
||||
github.com/jinzhu/inflection v1.0.0
|
||||
github.com/jinzhu/now v1.0.1
|
||||
github.com/lib/pq v1.1.1
|
||||
github.com/mattn/go-sqlite3 v2.0.1+incompatible
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd // indirect
|
||||
google.golang.org/appengine v1.4.0 // indirect
|
||||
)
|
29
vendor/github.com/jinzhu/gorm/go.sum
generated
vendored
29
vendor/github.com/jinzhu/gorm/go.sum
generated
vendored
@ -1,29 +0,0 @@
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
|
||||
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw=
|
||||
github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd h1:GGJVjV8waZKRHrgwvtH66z9ZGVurTD1MT0n1Bb+q4aM=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
5
vendor/github.com/jinzhu/gorm/main.go
generated
vendored
5
vendor/github.com/jinzhu/gorm/main.go
generated
vendored
@ -531,6 +531,11 @@ func (s *DB) Debug() *DB {
|
||||
// Transaction start a transaction as a block,
|
||||
// return error will rollback, otherwise to commit.
|
||||
func (s *DB) Transaction(fc func(tx *DB) error) (err error) {
|
||||
|
||||
if _, ok := s.db.(*sql.Tx); ok {
|
||||
return fc(s)
|
||||
}
|
||||
|
||||
panicked := true
|
||||
tx := s.Begin()
|
||||
defer func() {
|
||||
|
24
vendor/github.com/jinzhu/gorm/model_struct.go
generated
vendored
24
vendor/github.com/jinzhu/gorm/model_struct.go
generated
vendored
@ -152,6 +152,10 @@ func getForeignField(column string, fields []*StructField) *StructField {
|
||||
|
||||
// GetModelStruct get value's model struct, relationships based on struct and tag definition
|
||||
func (scope *Scope) GetModelStruct() *ModelStruct {
|
||||
return scope.getModelStruct(scope, make([]*StructField, 0))
|
||||
}
|
||||
|
||||
func (scope *Scope) getModelStruct(rootScope *Scope, allFields []*StructField) *ModelStruct {
|
||||
var modelStruct ModelStruct
|
||||
// Scope value can't be nil
|
||||
if scope.Value == nil {
|
||||
@ -237,7 +241,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
|
||||
field.IsNormal = true
|
||||
} else if _, ok := field.TagSettingsGet("EMBEDDED"); ok || fieldStruct.Anonymous {
|
||||
// is embedded struct
|
||||
for _, subField := range scope.New(fieldValue).GetModelStruct().StructFields {
|
||||
for _, subField := range scope.New(fieldValue).getModelStruct(rootScope, allFields).StructFields {
|
||||
subField = subField.clone()
|
||||
subField.Names = append([]string{fieldStruct.Name}, subField.Names...)
|
||||
if prefix, ok := field.TagSettingsGet("EMBEDDED_PREFIX"); ok {
|
||||
@ -261,6 +265,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
|
||||
}
|
||||
|
||||
modelStruct.StructFields = append(modelStruct.StructFields, subField)
|
||||
allFields = append(allFields, subField)
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
@ -394,7 +399,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
|
||||
} else {
|
||||
// generate foreign keys from defined association foreign keys
|
||||
for _, scopeFieldName := range associationForeignKeys {
|
||||
if foreignField := getForeignField(scopeFieldName, modelStruct.StructFields); foreignField != nil {
|
||||
if foreignField := getForeignField(scopeFieldName, allFields); foreignField != nil {
|
||||
foreignKeys = append(foreignKeys, associationType+foreignField.Name)
|
||||
associationForeignKeys = append(associationForeignKeys, foreignField.Name)
|
||||
}
|
||||
@ -406,13 +411,13 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
|
||||
for _, foreignKey := range foreignKeys {
|
||||
if strings.HasPrefix(foreignKey, associationType) {
|
||||
associationForeignKey := strings.TrimPrefix(foreignKey, associationType)
|
||||
if foreignField := getForeignField(associationForeignKey, modelStruct.StructFields); foreignField != nil {
|
||||
if foreignField := getForeignField(associationForeignKey, allFields); foreignField != nil {
|
||||
associationForeignKeys = append(associationForeignKeys, associationForeignKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(associationForeignKeys) == 0 && len(foreignKeys) == 1 {
|
||||
associationForeignKeys = []string{scope.PrimaryKey()}
|
||||
associationForeignKeys = []string{rootScope.PrimaryKey()}
|
||||
}
|
||||
} else if len(foreignKeys) != len(associationForeignKeys) {
|
||||
scope.Err(errors.New("invalid foreign keys, should have same length"))
|
||||
@ -422,7 +427,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
|
||||
|
||||
for idx, foreignKey := range foreignKeys {
|
||||
if foreignField := getForeignField(foreignKey, toFields); foreignField != nil {
|
||||
if associationField := getForeignField(associationForeignKeys[idx], modelStruct.StructFields); associationField != nil {
|
||||
if associationField := getForeignField(associationForeignKeys[idx], allFields); associationField != nil {
|
||||
// mark field as foreignkey, use global lock to avoid race
|
||||
structsLock.Lock()
|
||||
foreignField.IsForeignKey = true
|
||||
@ -502,7 +507,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
|
||||
} else {
|
||||
// generate foreign keys form association foreign keys
|
||||
for _, associationForeignKey := range tagAssociationForeignKeys {
|
||||
if foreignField := getForeignField(associationForeignKey, modelStruct.StructFields); foreignField != nil {
|
||||
if foreignField := getForeignField(associationForeignKey, allFields); foreignField != nil {
|
||||
foreignKeys = append(foreignKeys, associationType+foreignField.Name)
|
||||
associationForeignKeys = append(associationForeignKeys, foreignField.Name)
|
||||
}
|
||||
@ -514,13 +519,13 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
|
||||
for _, foreignKey := range foreignKeys {
|
||||
if strings.HasPrefix(foreignKey, associationType) {
|
||||
associationForeignKey := strings.TrimPrefix(foreignKey, associationType)
|
||||
if foreignField := getForeignField(associationForeignKey, modelStruct.StructFields); foreignField != nil {
|
||||
if foreignField := getForeignField(associationForeignKey, allFields); foreignField != nil {
|
||||
associationForeignKeys = append(associationForeignKeys, associationForeignKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(associationForeignKeys) == 0 && len(foreignKeys) == 1 {
|
||||
associationForeignKeys = []string{scope.PrimaryKey()}
|
||||
associationForeignKeys = []string{rootScope.PrimaryKey()}
|
||||
}
|
||||
} else if len(foreignKeys) != len(associationForeignKeys) {
|
||||
scope.Err(errors.New("invalid foreign keys, should have same length"))
|
||||
@ -530,7 +535,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
|
||||
|
||||
for idx, foreignKey := range foreignKeys {
|
||||
if foreignField := getForeignField(foreignKey, toFields); foreignField != nil {
|
||||
if scopeField := getForeignField(associationForeignKeys[idx], modelStruct.StructFields); scopeField != nil {
|
||||
if scopeField := getForeignField(associationForeignKeys[idx], allFields); scopeField != nil {
|
||||
// mark field as foreignkey, use global lock to avoid race
|
||||
structsLock.Lock()
|
||||
foreignField.IsForeignKey = true
|
||||
@ -630,6 +635,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
|
||||
}
|
||||
|
||||
modelStruct.StructFields = append(modelStruct.StructFields, field)
|
||||
allFields = append(allFields, field)
|
||||
}
|
||||
}
|
||||
|
||||
|
28
vendor/github.com/jinzhu/gorm/scope.go
generated
vendored
28
vendor/github.com/jinzhu/gorm/scope.go
generated
vendored
@ -590,7 +590,7 @@ func (scope *Scope) buildCondition(clause map[string]interface{}, include bool)
|
||||
}
|
||||
scopeQuotedTableName := newScope.QuotedTableName()
|
||||
for _, field := range newScope.Fields() {
|
||||
if !field.IsIgnored && !field.IsBlank {
|
||||
if !field.IsIgnored && !field.IsBlank && field.Relationship == nil {
|
||||
sqls = append(sqls, fmt.Sprintf("(%v.%v %s %v)", scopeQuotedTableName, scope.Quote(field.DBName), equalSQL, scope.AddToVars(field.Field.Interface())))
|
||||
}
|
||||
}
|
||||
@ -913,21 +913,25 @@ func (scope *Scope) updatedAttrsWithValues(value interface{}) (results map[strin
|
||||
results = map[string]interface{}{}
|
||||
|
||||
for key, value := range convertInterfaceToMap(value, true, scope.db) {
|
||||
if field, ok := scope.FieldByName(key); ok && scope.changeableField(field) {
|
||||
if _, ok := value.(*SqlExpr); ok {
|
||||
hasUpdate = true
|
||||
results[field.DBName] = value
|
||||
} else {
|
||||
err := field.Set(value)
|
||||
if field.IsNormal && !field.IsIgnored {
|
||||
if field, ok := scope.FieldByName(key); ok {
|
||||
if scope.changeableField(field) {
|
||||
if _, ok := value.(*SqlExpr); ok {
|
||||
hasUpdate = true
|
||||
if err == ErrUnaddressable {
|
||||
results[field.DBName] = value
|
||||
} else {
|
||||
results[field.DBName] = field.Field.Interface()
|
||||
results[field.DBName] = value
|
||||
} else {
|
||||
err := field.Set(value)
|
||||
if field.IsNormal && !field.IsIgnored {
|
||||
hasUpdate = true
|
||||
if err == ErrUnaddressable {
|
||||
results[field.DBName] = value
|
||||
} else {
|
||||
results[field.DBName] = field.Field.Interface()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
results[key] = value
|
||||
}
|
||||
}
|
||||
return
|
||||
|
52
vendor/github.com/jinzhu/gorm/search.go
generated
vendored
52
vendor/github.com/jinzhu/gorm/search.go
generated
vendored
@ -32,7 +32,57 @@ type searchPreload struct {
|
||||
}
|
||||
|
||||
func (s *search) clone() *search {
|
||||
clone := *s
|
||||
clone := search{
|
||||
db: s.db,
|
||||
whereConditions: make([]map[string]interface{}, len(s.whereConditions)),
|
||||
orConditions: make([]map[string]interface{}, len(s.orConditions)),
|
||||
notConditions: make([]map[string]interface{}, len(s.notConditions)),
|
||||
havingConditions: make([]map[string]interface{}, len(s.havingConditions)),
|
||||
joinConditions: make([]map[string]interface{}, len(s.joinConditions)),
|
||||
initAttrs: make([]interface{}, len(s.initAttrs)),
|
||||
assignAttrs: make([]interface{}, len(s.assignAttrs)),
|
||||
selects: s.selects,
|
||||
omits: make([]string, len(s.omits)),
|
||||
orders: make([]interface{}, len(s.orders)),
|
||||
preload: make([]searchPreload, len(s.preload)),
|
||||
offset: s.offset,
|
||||
limit: s.limit,
|
||||
group: s.group,
|
||||
tableName: s.tableName,
|
||||
raw: s.raw,
|
||||
Unscoped: s.Unscoped,
|
||||
ignoreOrderQuery: s.ignoreOrderQuery,
|
||||
}
|
||||
for i, value := range s.whereConditions {
|
||||
clone.whereConditions[i] = value
|
||||
}
|
||||
for i, value := range s.orConditions {
|
||||
clone.orConditions[i] = value
|
||||
}
|
||||
for i, value := range s.notConditions {
|
||||
clone.notConditions[i] = value
|
||||
}
|
||||
for i, value := range s.havingConditions {
|
||||
clone.havingConditions[i] = value
|
||||
}
|
||||
for i, value := range s.joinConditions {
|
||||
clone.joinConditions[i] = value
|
||||
}
|
||||
for i, value := range s.initAttrs {
|
||||
clone.initAttrs[i] = value
|
||||
}
|
||||
for i, value := range s.assignAttrs {
|
||||
clone.assignAttrs[i] = value
|
||||
}
|
||||
for i, value := range s.omits {
|
||||
clone.omits[i] = value
|
||||
}
|
||||
for i, value := range s.orders {
|
||||
clone.orders[i] = value
|
||||
}
|
||||
for i, value := range s.preload {
|
||||
clone.preload[i] = value
|
||||
}
|
||||
return &clone
|
||||
}
|
||||
|
||||
|
5
vendor/github.com/jinzhu/gorm/wercker.yml
generated
vendored
5
vendor/github.com/jinzhu/gorm/wercker.yml
generated
vendored
@ -142,11 +142,6 @@ build:
|
||||
code: |
|
||||
GORM_DIALECT=postgres GORM_DSN="host=postgres93 user=gorm password=gorm DB.name=gorm port=5432 sslmode=disable" go test -race ./...
|
||||
|
||||
- script:
|
||||
name: test mssql
|
||||
code: |
|
||||
GORM_DIALECT=mssql GORM_DSN="sqlserver://gorm:LoremIpsum86@mssql:1433?database=gorm" go test -race ./...
|
||||
|
||||
- script:
|
||||
name: codecov
|
||||
code: |
|
||||
|
1
vendor/github.com/jinzhu/inflection/go.mod
generated
vendored
1
vendor/github.com/jinzhu/inflection/go.mod
generated
vendored
@ -1 +0,0 @@
|
||||
module github.com/jinzhu/inflection
|
1
vendor/github.com/jmoiron/sqlx/.gitignore
generated
vendored
1
vendor/github.com/jmoiron/sqlx/.gitignore
generated
vendored
@ -6,6 +6,7 @@
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
.idea
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
|
5
vendor/github.com/jmoiron/sqlx/.travis.yml
generated
vendored
5
vendor/github.com/jmoiron/sqlx/.travis.yml
generated
vendored
@ -18,9 +18,8 @@ before_install:
|
||||
|
||||
# go versions to test
|
||||
go:
|
||||
- "1.8"
|
||||
- "1.9"
|
||||
- "1.10.x"
|
||||
- "1.15.x"
|
||||
- "1.16.x"
|
||||
|
||||
# run tests w/ coverage
|
||||
script:
|
||||
|
58
vendor/github.com/jmoiron/sqlx/README.md
generated
vendored
58
vendor/github.com/jmoiron/sqlx/README.md
generated
vendored
@ -15,30 +15,34 @@ Major additional concepts are:
|
||||
* `Get` and `Select` to go quickly from query to struct/slice
|
||||
|
||||
In addition to the [godoc API documentation](http://godoc.org/github.com/jmoiron/sqlx),
|
||||
there is also some [standard documentation](http://jmoiron.github.io/sqlx/) that
|
||||
there is also some [user documentation](http://jmoiron.github.io/sqlx/) that
|
||||
explains how to use `database/sql` along with sqlx.
|
||||
|
||||
## Recent Changes
|
||||
|
||||
* The [introduction](https://github.com/jmoiron/sqlx/pull/387) of `sql.ColumnType` sets the required minimum Go version to 1.8.
|
||||
1.3.0:
|
||||
|
||||
* sqlx/types.JsonText has been renamed to JSONText to follow Go naming conventions.
|
||||
* `sqlx.DB.Connx(context.Context) *sqlx.Conn`
|
||||
* `sqlx.BindDriver(driverName, bindType)`
|
||||
* support for `[]map[string]interface{}` to do "batch" insertions
|
||||
* allocation & perf improvements for `sqlx.In`
|
||||
|
||||
This breaks backwards compatibility, but it's in a way that is trivially fixable
|
||||
(`s/JsonText/JSONText/g`). The `types` package is both experimental and not in
|
||||
active development currently.
|
||||
DB.Connx returns an `sqlx.Conn`, which is an `sql.Conn`-alike consistent with
|
||||
sqlx's wrapping of other types.
|
||||
|
||||
* Using Go 1.6 and below with `types.JSONText` and `types.GzippedText` can be _potentially unsafe_, **especially** when used with common auto-scan sqlx idioms like `Select` and `Get`. See [golang bug #13905](https://github.com/golang/go/issues/13905).
|
||||
`BindDriver` allows users to control the bindvars that sqlx will use for drivers,
|
||||
and add new drivers at runtime. This results in a very slight performance hit
|
||||
when resolving the driver into a bind type (~40ns per call), but it allows users
|
||||
to specify what bindtype their driver uses even when sqlx has not been updated
|
||||
to know about it by default.
|
||||
|
||||
### Backwards Compatibility
|
||||
|
||||
There is no Go1-like promise of absolute stability, but I take the issue seriously
|
||||
and will maintain the library in a compatible state unless vital bugs prevent me
|
||||
from doing so. Since [#59](https://github.com/jmoiron/sqlx/issues/59) and
|
||||
[#60](https://github.com/jmoiron/sqlx/issues/60) necessitated breaking behavior,
|
||||
a wider API cleanup was done at the time of fixing. It's possible this will happen
|
||||
in future; if it does, a git tag will be provided for users requiring the old
|
||||
behavior to continue to use it until such a time as they can migrate.
|
||||
Compatibility with the most recent two versions of Go is a requirement for any
|
||||
new changes. Compatibility beyond that is not guaranteed.
|
||||
|
||||
Versioning is done with Go modules. Breaking changes (eg. removing deprecated API)
|
||||
will get major version number bumps.
|
||||
|
||||
## install
|
||||
|
||||
@ -102,7 +106,7 @@ type Place struct {
|
||||
}
|
||||
|
||||
func main() {
|
||||
// this Pings the database trying to connect, panics on error
|
||||
// this Pings the database trying to connect
|
||||
// use sqlx.Open() for sql.Open() semantics
|
||||
db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable")
|
||||
if err != nil {
|
||||
@ -182,6 +186,28 @@ func main() {
|
||||
// as the name -> db mapping, so struct fields are lowercased and the `db` tag
|
||||
// is taken into consideration.
|
||||
rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:first_name`, jason)
|
||||
|
||||
|
||||
// batch insert
|
||||
|
||||
// batch insert with structs
|
||||
personStructs := []Person{
|
||||
{FirstName: "Ardie", LastName: "Savea", Email: "asavea@ab.co.nz"},
|
||||
{FirstName: "Sonny Bill", LastName: "Williams", Email: "sbw@ab.co.nz"},
|
||||
{FirstName: "Ngani", LastName: "Laumape", Email: "nlaumape@ab.co.nz"},
|
||||
}
|
||||
|
||||
_, err = db.NamedExec(`INSERT INTO person (first_name, last_name, email)
|
||||
VALUES (:first_name, :last_name, :email)`, personStructs)
|
||||
|
||||
// batch insert with maps
|
||||
personMaps := []map[string]interface{}{
|
||||
{"first_name": "Ardie", "last_name": "Savea", "email": "asavea@ab.co.nz"},
|
||||
{"first_name": "Sonny Bill", "last_name": "Williams", "email": "sbw@ab.co.nz"},
|
||||
{"first_name": "Ngani", "last_name": "Laumape", "email": "nlaumape@ab.co.nz"},
|
||||
}
|
||||
|
||||
_, err = db.NamedExec(`INSERT INTO person (first_name, last_name, email)
|
||||
VALUES (:first_name, :last_name, :email)`, personMaps)
|
||||
}
|
||||
```
|
||||
|
||||
|
94
vendor/github.com/jmoiron/sqlx/bind.go
generated
vendored
94
vendor/github.com/jmoiron/sqlx/bind.go
generated
vendored
@ -7,6 +7,7 @@ import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/jmoiron/sqlx/reflectx"
|
||||
)
|
||||
@ -20,21 +21,36 @@ const (
|
||||
AT
|
||||
)
|
||||
|
||||
var defaultBinds = map[int][]string{
|
||||
DOLLAR: []string{"postgres", "pgx", "pq-timeouts", "cloudsqlpostgres", "ql", "nrpostgres", "cockroach"},
|
||||
QUESTION: []string{"mysql", "sqlite3", "nrmysql", "nrsqlite3"},
|
||||
NAMED: []string{"oci8", "ora", "goracle", "godror"},
|
||||
AT: []string{"sqlserver"},
|
||||
}
|
||||
|
||||
var binds sync.Map
|
||||
|
||||
func init() {
|
||||
for bind, drivers := range defaultBinds {
|
||||
for _, driver := range drivers {
|
||||
BindDriver(driver, bind)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// BindType returns the bindtype for a given database given a drivername.
|
||||
func BindType(driverName string) int {
|
||||
switch driverName {
|
||||
case "postgres", "pgx", "pq-timeouts", "cloudsqlpostgres":
|
||||
return DOLLAR
|
||||
case "mysql":
|
||||
return QUESTION
|
||||
case "sqlite3":
|
||||
return QUESTION
|
||||
case "oci8", "ora", "goracle":
|
||||
return NAMED
|
||||
case "sqlserver":
|
||||
return AT
|
||||
itype, ok := binds.Load(driverName)
|
||||
if !ok {
|
||||
return UNKNOWN
|
||||
}
|
||||
return UNKNOWN
|
||||
return itype.(int)
|
||||
}
|
||||
|
||||
// BindDriver sets the BindType for driverName to bindType.
|
||||
func BindDriver(driverName string, bindType int) {
|
||||
binds.Store(driverName, bindType)
|
||||
}
|
||||
|
||||
// FIXME: this should be able to be tolerant of escaped ?'s in queries without
|
||||
@ -98,6 +114,28 @@ func rebindBuff(bindType int, query string) string {
|
||||
return rqb.String()
|
||||
}
|
||||
|
||||
func asSliceForIn(i interface{}) (v reflect.Value, ok bool) {
|
||||
if i == nil {
|
||||
return reflect.Value{}, false
|
||||
}
|
||||
|
||||
v = reflect.ValueOf(i)
|
||||
t := reflectx.Deref(v.Type())
|
||||
|
||||
// Only expand slices
|
||||
if t.Kind() != reflect.Slice {
|
||||
return reflect.Value{}, false
|
||||
}
|
||||
|
||||
// []byte is a driver.Value type so it should not be expanded
|
||||
if t == reflect.TypeOf([]byte{}) {
|
||||
return reflect.Value{}, false
|
||||
|
||||
}
|
||||
|
||||
return v, true
|
||||
}
|
||||
|
||||
// In expands slice values in args, returning the modified query string
|
||||
// and a new arg list that can be executed by a database. The `query` should
|
||||
// use the `?` bindVar. The return value uses the `?` bindVar.
|
||||
@ -113,17 +151,25 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
|
||||
var flatArgsCount int
|
||||
var anySlices bool
|
||||
|
||||
meta := make([]argMeta, len(args))
|
||||
var stackMeta [32]argMeta
|
||||
|
||||
var meta []argMeta
|
||||
if len(args) <= len(stackMeta) {
|
||||
meta = stackMeta[:len(args)]
|
||||
} else {
|
||||
meta = make([]argMeta, len(args))
|
||||
}
|
||||
|
||||
for i, arg := range args {
|
||||
if a, ok := arg.(driver.Valuer); ok {
|
||||
arg, _ = a.Value()
|
||||
var err error
|
||||
arg, err = a.Value()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
v := reflect.ValueOf(arg)
|
||||
t := reflectx.Deref(v.Type())
|
||||
|
||||
// []byte is a driver.Value type so it should not be expanded
|
||||
if t.Kind() == reflect.Slice && t != reflect.TypeOf([]byte{}) {
|
||||
if v, ok := asSliceForIn(arg); ok {
|
||||
meta[i].length = v.Len()
|
||||
meta[i].v = v
|
||||
|
||||
@ -146,7 +192,9 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
|
||||
}
|
||||
|
||||
newArgs := make([]interface{}, 0, flatArgsCount)
|
||||
buf := make([]byte, 0, len(query)+len(", ?")*flatArgsCount)
|
||||
|
||||
var buf strings.Builder
|
||||
buf.Grow(len(query) + len(", ?")*flatArgsCount)
|
||||
|
||||
var arg, offset int
|
||||
|
||||
@ -172,10 +220,10 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
|
||||
}
|
||||
|
||||
// write everything up to and including our ? character
|
||||
buf = append(buf, query[:offset+i+1]...)
|
||||
buf.WriteString(query[:offset+i+1])
|
||||
|
||||
for si := 1; si < argMeta.length; si++ {
|
||||
buf = append(buf, ", ?"...)
|
||||
buf.WriteString(", ?")
|
||||
}
|
||||
|
||||
newArgs = appendReflectSlice(newArgs, argMeta.v, argMeta.length)
|
||||
@ -186,13 +234,13 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
|
||||
offset = 0
|
||||
}
|
||||
|
||||
buf = append(buf, query...)
|
||||
buf.WriteString(query)
|
||||
|
||||
if arg < len(meta) {
|
||||
return "", nil, errors.New("number of bindVars less than number arguments")
|
||||
}
|
||||
|
||||
return string(buf), newArgs, nil
|
||||
return buf.String(), newArgs, nil
|
||||
}
|
||||
|
||||
func appendReflectSlice(args []interface{}, v reflect.Value, vlen int) []interface{} {
|
||||
|
7
vendor/github.com/jmoiron/sqlx/go.mod
generated
vendored
7
vendor/github.com/jmoiron/sqlx/go.mod
generated
vendored
@ -1,7 +0,0 @@
|
||||
module github.com/jmoiron/sqlx
|
||||
|
||||
require (
|
||||
github.com/go-sql-driver/mysql v1.4.0
|
||||
github.com/lib/pq v1.0.0
|
||||
github.com/mattn/go-sqlite3 v1.9.0
|
||||
)
|
6
vendor/github.com/jmoiron/sqlx/go.sum
generated
vendored
6
vendor/github.com/jmoiron/sqlx/go.sum
generated
vendored
@ -1,6 +0,0 @@
|
||||
github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
116
vendor/github.com/jmoiron/sqlx/named.go
generated
vendored
116
vendor/github.com/jmoiron/sqlx/named.go
generated
vendored
@ -12,10 +12,12 @@ package sqlx
|
||||
// * bindArgs, bindMapArgs, bindAnyArgs - given a list of names, return an arglist
|
||||
//
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"unicode"
|
||||
|
||||
@ -144,8 +146,22 @@ func prepareNamed(p namedPreparer, query string) (*NamedStmt, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// convertMapStringInterface attempts to convert v to map[string]interface{}.
|
||||
// Unlike v.(map[string]interface{}), this function works on named types that
|
||||
// are convertible to map[string]interface{} as well.
|
||||
func convertMapStringInterface(v interface{}) (map[string]interface{}, bool) {
|
||||
var m map[string]interface{}
|
||||
mtype := reflect.TypeOf(m)
|
||||
t := reflect.TypeOf(v)
|
||||
if !t.ConvertibleTo(mtype) {
|
||||
return nil, false
|
||||
}
|
||||
return reflect.ValueOf(v).Convert(mtype).Interface().(map[string]interface{}), true
|
||||
|
||||
}
|
||||
|
||||
func bindAnyArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{}, error) {
|
||||
if maparg, ok := arg.(map[string]interface{}); ok {
|
||||
if maparg, ok := convertMapStringInterface(arg); ok {
|
||||
return bindMapArgs(names, maparg)
|
||||
}
|
||||
return bindArgs(names, arg, m)
|
||||
@ -200,7 +216,7 @@ func bindStruct(bindType int, query string, arg interface{}, m *reflectx.Mapper)
|
||||
return "", []interface{}{}, err
|
||||
}
|
||||
|
||||
arglist, err := bindArgs(names, arg, m)
|
||||
arglist, err := bindAnyArgs(names, arg, m)
|
||||
if err != nil {
|
||||
return "", []interface{}{}, err
|
||||
}
|
||||
@ -208,6 +224,82 @@ func bindStruct(bindType int, query string, arg interface{}, m *reflectx.Mapper)
|
||||
return bound, arglist, nil
|
||||
}
|
||||
|
||||
var valuesReg = regexp.MustCompile(`\)\s*(?i)VALUES\s*\(`)
|
||||
|
||||
func findMatchingClosingBracketIndex(s string) int {
|
||||
count := 0
|
||||
for i, ch := range s {
|
||||
if ch == '(' {
|
||||
count++
|
||||
}
|
||||
if ch == ')' {
|
||||
count--
|
||||
if count == 0 {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func fixBound(bound string, loop int) string {
|
||||
loc := valuesReg.FindStringIndex(bound)
|
||||
// defensive guard when "VALUES (...)" not found
|
||||
if len(loc) < 2 {
|
||||
return bound
|
||||
}
|
||||
|
||||
openingBracketIndex := loc[1] - 1
|
||||
index := findMatchingClosingBracketIndex(bound[openingBracketIndex:])
|
||||
// defensive guard. must have closing bracket
|
||||
if index == 0 {
|
||||
return bound
|
||||
}
|
||||
closingBracketIndex := openingBracketIndex + index + 1
|
||||
|
||||
var buffer bytes.Buffer
|
||||
|
||||
buffer.WriteString(bound[0:closingBracketIndex])
|
||||
for i := 0; i < loop-1; i++ {
|
||||
buffer.WriteString(",")
|
||||
buffer.WriteString(bound[openingBracketIndex:closingBracketIndex])
|
||||
}
|
||||
buffer.WriteString(bound[closingBracketIndex:])
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// bindArray binds a named parameter query with fields from an array or slice of
|
||||
// structs argument.
|
||||
func bindArray(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
|
||||
// do the initial binding with QUESTION; if bindType is not question,
|
||||
// we can rebind it at the end.
|
||||
bound, names, err := compileNamedQuery([]byte(query), QUESTION)
|
||||
if err != nil {
|
||||
return "", []interface{}{}, err
|
||||
}
|
||||
arrayValue := reflect.ValueOf(arg)
|
||||
arrayLen := arrayValue.Len()
|
||||
if arrayLen == 0 {
|
||||
return "", []interface{}{}, fmt.Errorf("length of array is 0: %#v", arg)
|
||||
}
|
||||
var arglist = make([]interface{}, 0, len(names)*arrayLen)
|
||||
for i := 0; i < arrayLen; i++ {
|
||||
elemArglist, err := bindAnyArgs(names, arrayValue.Index(i).Interface(), m)
|
||||
if err != nil {
|
||||
return "", []interface{}{}, err
|
||||
}
|
||||
arglist = append(arglist, elemArglist...)
|
||||
}
|
||||
if arrayLen > 1 {
|
||||
bound = fixBound(bound, arrayLen)
|
||||
}
|
||||
// adjust binding type if we weren't on question
|
||||
if bindType != QUESTION {
|
||||
bound = Rebind(bindType, bound)
|
||||
}
|
||||
return bound, arglist, nil
|
||||
}
|
||||
|
||||
// bindMap binds a named parameter query with a map of arguments.
|
||||
func bindMap(bindType int, query string, args map[string]interface{}) (string, []interface{}, error) {
|
||||
bound, names, err := compileNamedQuery([]byte(query), bindType)
|
||||
@ -259,7 +351,7 @@ func compileNamedQuery(qs []byte, bindType int) (query string, names []string, e
|
||||
}
|
||||
inName = true
|
||||
name = []byte{}
|
||||
} else if inName && i > 0 && b == '=' {
|
||||
} else if inName && i > 0 && b == '=' && len(name) == 0 {
|
||||
rebound = append(rebound, ':', '=')
|
||||
inName = false
|
||||
continue
|
||||
@ -327,10 +419,20 @@ func Named(query string, arg interface{}) (string, []interface{}, error) {
|
||||
}
|
||||
|
||||
func bindNamedMapper(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
|
||||
if maparg, ok := arg.(map[string]interface{}); ok {
|
||||
return bindMap(bindType, query, maparg)
|
||||
t := reflect.TypeOf(arg)
|
||||
k := t.Kind()
|
||||
switch {
|
||||
case k == reflect.Map && t.Key().Kind() == reflect.String:
|
||||
m, ok := convertMapStringInterface(arg)
|
||||
if !ok {
|
||||
return "", nil, fmt.Errorf("sqlx.bindNamedMapper: unsupported map type: %T", arg)
|
||||
}
|
||||
return bindMap(bindType, query, m)
|
||||
case k == reflect.Array || k == reflect.Slice:
|
||||
return bindArray(bindType, query, arg, m)
|
||||
default:
|
||||
return bindStruct(bindType, query, arg, m)
|
||||
}
|
||||
return bindStruct(bindType, query, arg, m)
|
||||
}
|
||||
|
||||
// NamedQuery binds a named query and then runs Query on the result using the
|
||||
@ -346,7 +448,7 @@ func NamedQuery(e Ext, query string, arg interface{}) (*Rows, error) {
|
||||
|
||||
// NamedExec uses BindStruct to get a query executable by the driver and
|
||||
// then runs Exec on the result. Returns an error from the binding
|
||||
// or the query excution itself.
|
||||
// or the query execution itself.
|
||||
func NamedExec(e Ext, query string, arg interface{}) (sql.Result, error) {
|
||||
q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
|
||||
if err != nil {
|
||||
|
2
vendor/github.com/jmoiron/sqlx/named_context.go
generated
vendored
2
vendor/github.com/jmoiron/sqlx/named_context.go
generated
vendored
@ -122,7 +122,7 @@ func NamedQueryContext(ctx context.Context, e ExtContext, query string, arg inte
|
||||
|
||||
// NamedExecContext uses BindStruct to get a query executable by the driver and
|
||||
// then runs Exec on the result. Returns an error from the binding
|
||||
// or the query excution itself.
|
||||
// or the query execution itself.
|
||||
func NamedExecContext(ctx context.Context, e ExtContext, query string, arg interface{}) (sql.Result, error) {
|
||||
q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
|
||||
if err != nil {
|
||||
|
15
vendor/github.com/jmoiron/sqlx/reflectx/reflect.go
generated
vendored
15
vendor/github.com/jmoiron/sqlx/reflectx/reflect.go
generated
vendored
@ -269,9 +269,7 @@ type typeQueue struct {
|
||||
// A copying append that creates a new slice each time.
|
||||
func apnd(is []int, i int) []int {
|
||||
x := make([]int, len(is)+1)
|
||||
for p, n := range is {
|
||||
x[p] = n
|
||||
}
|
||||
copy(x, is)
|
||||
x[len(x)-1] = i
|
||||
return x
|
||||
}
|
||||
@ -431,9 +429,14 @@ QueueLoop:
|
||||
|
||||
flds := &StructMap{Index: m, Tree: root, Paths: map[string]*FieldInfo{}, Names: map[string]*FieldInfo{}}
|
||||
for _, fi := range flds.Index {
|
||||
flds.Paths[fi.Path] = fi
|
||||
if fi.Name != "" && !fi.Embedded {
|
||||
flds.Names[fi.Path] = fi
|
||||
// check if nothing has already been pushed with the same path
|
||||
// sometimes you can choose to override a type using embedded struct
|
||||
fld, ok := flds.Paths[fi.Path]
|
||||
if !ok || fld.Embedded {
|
||||
flds.Paths[fi.Path] = fi
|
||||
if fi.Name != "" && !fi.Embedded {
|
||||
flds.Names[fi.Path] = fi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
32
vendor/github.com/jmoiron/sqlx/sqlx.go
generated
vendored
32
vendor/github.com/jmoiron/sqlx/sqlx.go
generated
vendored
@ -64,11 +64,7 @@ func isScannable(t reflect.Type) bool {
|
||||
|
||||
// it's not important that we use the right mapper for this particular object,
|
||||
// we're only concerned on how many exported fields this struct has
|
||||
m := mapper()
|
||||
if len(m.TypeMap(t).Index) == 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return len(mapper().TypeMap(t).Index) == 0
|
||||
}
|
||||
|
||||
// ColScanner is an interface used by MapScan and SliceScan
|
||||
@ -149,15 +145,15 @@ func isUnsafe(i interface{}) bool {
|
||||
}
|
||||
|
||||
func mapperFor(i interface{}) *reflectx.Mapper {
|
||||
switch i.(type) {
|
||||
switch i := i.(type) {
|
||||
case DB:
|
||||
return i.(DB).Mapper
|
||||
return i.Mapper
|
||||
case *DB:
|
||||
return i.(*DB).Mapper
|
||||
return i.Mapper
|
||||
case Tx:
|
||||
return i.(Tx).Mapper
|
||||
return i.Mapper
|
||||
case *Tx:
|
||||
return i.(*Tx).Mapper
|
||||
return i.Mapper
|
||||
default:
|
||||
return mapper()
|
||||
}
|
||||
@ -380,6 +376,14 @@ func (db *DB) PrepareNamed(query string) (*NamedStmt, error) {
|
||||
return prepareNamed(db, query)
|
||||
}
|
||||
|
||||
// Conn is a wrapper around sql.Conn with extra functionality
|
||||
type Conn struct {
|
||||
*sql.Conn
|
||||
driverName string
|
||||
unsafe bool
|
||||
Mapper *reflectx.Mapper
|
||||
}
|
||||
|
||||
// Tx is an sqlx wrapper around sql.Tx with extra functionality
|
||||
type Tx struct {
|
||||
*sql.Tx
|
||||
@ -874,9 +878,10 @@ func structOnlyError(t reflect.Type) error {
|
||||
}
|
||||
|
||||
// scanAll scans all rows into a destination, which must be a slice of any
|
||||
// type. If the destination slice type is a Struct, then StructScan will be
|
||||
// used on each row. If the destination is some other kind of base type, then
|
||||
// each row must only have one column which can scan into that type. This
|
||||
// type. It resets the slice length to zero before appending each element to
|
||||
// the slice. If the destination slice type is a Struct, then StructScan will
|
||||
// be used on each row. If the destination is some other kind of base type,
|
||||
// then each row must only have one column which can scan into that type. This
|
||||
// allows you to do something like:
|
||||
//
|
||||
// rows, _ := db.Query("select id from people;")
|
||||
@ -906,6 +911,7 @@ func scanAll(rows rowsi, dest interface{}, structOnly bool) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
direct.SetLen(0)
|
||||
|
||||
isPtr := slice.Elem().Kind() == reflect.Ptr
|
||||
base := reflectx.Deref(slice.Elem())
|
||||
|
68
vendor/github.com/jmoiron/sqlx/sqlx_context.go
generated
vendored
68
vendor/github.com/jmoiron/sqlx/sqlx_context.go
generated
vendored
@ -208,6 +208,74 @@ func (db *DB) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
|
||||
return &Tx{Tx: tx, driverName: db.driverName, unsafe: db.unsafe, Mapper: db.Mapper}, err
|
||||
}
|
||||
|
||||
// Connx returns an *sqlx.Conn instead of an *sql.Conn.
|
||||
func (db *DB) Connx(ctx context.Context) (*Conn, error) {
|
||||
conn, err := db.DB.Conn(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Conn{Conn: conn, driverName: db.driverName, unsafe: db.unsafe, Mapper: db.Mapper}, nil
|
||||
}
|
||||
|
||||
// BeginTxx begins a transaction and returns an *sqlx.Tx instead of an
|
||||
// *sql.Tx.
|
||||
//
|
||||
// The provided context is used until the transaction is committed or rolled
|
||||
// back. If the context is canceled, the sql package will roll back the
|
||||
// transaction. Tx.Commit will return an error if the context provided to
|
||||
// BeginxContext is canceled.
|
||||
func (c *Conn) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
|
||||
tx, err := c.Conn.BeginTx(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Tx{Tx: tx, driverName: c.driverName, unsafe: c.unsafe, Mapper: c.Mapper}, err
|
||||
}
|
||||
|
||||
// SelectContext using this Conn.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func (c *Conn) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
|
||||
return SelectContext(ctx, c, dest, query, args...)
|
||||
}
|
||||
|
||||
// GetContext using this Conn.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
// An error is returned if the result set is empty.
|
||||
func (c *Conn) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
|
||||
return GetContext(ctx, c, dest, query, args...)
|
||||
}
|
||||
|
||||
// PreparexContext returns an sqlx.Stmt instead of a sql.Stmt.
|
||||
//
|
||||
// The provided context is used for the preparation of the statement, not for
|
||||
// the execution of the statement.
|
||||
func (c *Conn) PreparexContext(ctx context.Context, query string) (*Stmt, error) {
|
||||
return PreparexContext(ctx, c, query)
|
||||
}
|
||||
|
||||
// QueryxContext queries the database and returns an *sqlx.Rows.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func (c *Conn) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
|
||||
r, err := c.Conn.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Rows{Rows: r, unsafe: c.unsafe, Mapper: c.Mapper}, err
|
||||
}
|
||||
|
||||
// QueryRowxContext queries the database and returns an *sqlx.Row.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func (c *Conn) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
|
||||
rows, err := c.Conn.QueryContext(ctx, query, args...)
|
||||
return &Row{rows: rows, err: err, unsafe: c.unsafe, Mapper: c.Mapper}
|
||||
}
|
||||
|
||||
// Rebind a query within a Conn's bindvar type.
|
||||
func (c *Conn) Rebind(query string) string {
|
||||
return Rebind(BindType(c.driverName), query)
|
||||
}
|
||||
|
||||
// StmtxContext returns a version of the prepared statement which runs within a
|
||||
// transaction. Provided stmt can be either *sql.Stmt or *sqlx.Stmt.
|
||||
func (tx *Tx) StmtxContext(ctx context.Context, stmt interface{}) *Stmt {
|
||||
|
27
vendor/golang.org/x/crypto/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/crypto/LICENSE
generated
vendored
Normal 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.
|
22
vendor/golang.org/x/crypto/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/crypto/PATENTS
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
71
vendor/golang.org/x/crypto/ed25519/ed25519.go
generated
vendored
Normal file
71
vendor/golang.org/x/crypto/ed25519/ed25519.go
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright 2019 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 ed25519 implements the Ed25519 signature algorithm. See
|
||||
// https://ed25519.cr.yp.to/.
|
||||
//
|
||||
// These functions are also compatible with the “Ed25519” function defined in
|
||||
// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
|
||||
// representation includes a public key suffix to make multiple signing
|
||||
// operations with the same key more efficient. This package refers to the RFC
|
||||
// 8032 private key as the “seed”.
|
||||
//
|
||||
// Beginning with Go 1.13, the functionality of this package was moved to the
|
||||
// standard library as crypto/ed25519. This package only acts as a compatibility
|
||||
// wrapper.
|
||||
package ed25519
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
// PublicKeySize is the size, in bytes, of public keys as used in this package.
|
||||
PublicKeySize = 32
|
||||
// PrivateKeySize is the size, in bytes, of private keys as used in this package.
|
||||
PrivateKeySize = 64
|
||||
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
||||
SignatureSize = 64
|
||||
// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
|
||||
SeedSize = 32
|
||||
)
|
||||
|
||||
// PublicKey is the type of Ed25519 public keys.
|
||||
//
|
||||
// This type is an alias for crypto/ed25519's PublicKey type.
|
||||
// See the crypto/ed25519 package for the methods on this type.
|
||||
type PublicKey = ed25519.PublicKey
|
||||
|
||||
// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
|
||||
//
|
||||
// This type is an alias for crypto/ed25519's PrivateKey type.
|
||||
// See the crypto/ed25519 package for the methods on this type.
|
||||
type PrivateKey = ed25519.PrivateKey
|
||||
|
||||
// GenerateKey generates a public/private key pair using entropy from rand.
|
||||
// If rand is nil, crypto/rand.Reader will be used.
|
||||
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
|
||||
return ed25519.GenerateKey(rand)
|
||||
}
|
||||
|
||||
// NewKeyFromSeed calculates a private key from a seed. It will panic if
|
||||
// len(seed) is not SeedSize. This function is provided for interoperability
|
||||
// with RFC 8032. RFC 8032's private keys correspond to seeds in this
|
||||
// package.
|
||||
func NewKeyFromSeed(seed []byte) PrivateKey {
|
||||
return ed25519.NewKeyFromSeed(seed)
|
||||
}
|
||||
|
||||
// Sign signs the message with privateKey and returns a signature. It will
|
||||
// panic if len(privateKey) is not PrivateKeySize.
|
||||
func Sign(privateKey PrivateKey, message []byte) []byte {
|
||||
return ed25519.Sign(privateKey, message)
|
||||
}
|
||||
|
||||
// Verify reports whether sig is a valid signature of message by publicKey. It
|
||||
// will panic if len(publicKey) is not PublicKeySize.
|
||||
func Verify(publicKey PublicKey, message, sig []byte) bool {
|
||||
return ed25519.Verify(publicKey, message, sig)
|
||||
}
|
62
vendor/golang.org/x/crypto/sha3/doc.go
generated
vendored
Normal file
62
vendor/golang.org/x/crypto/sha3/doc.go
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright 2014 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 sha3 implements the SHA-3 fixed-output-length hash functions and
|
||||
// the SHAKE variable-output-length hash functions defined by FIPS-202.
|
||||
//
|
||||
// Both types of hash function use the "sponge" construction and the Keccak
|
||||
// permutation. For a detailed specification see http://keccak.noekeon.org/
|
||||
//
|
||||
// # Guidance
|
||||
//
|
||||
// If you aren't sure what function you need, use SHAKE256 with at least 64
|
||||
// bytes of output. The SHAKE instances are faster than the SHA3 instances;
|
||||
// the latter have to allocate memory to conform to the hash.Hash interface.
|
||||
//
|
||||
// If you need a secret-key MAC (message authentication code), prepend the
|
||||
// secret key to the input, hash with SHAKE256 and read at least 32 bytes of
|
||||
// output.
|
||||
//
|
||||
// # Security strengths
|
||||
//
|
||||
// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security
|
||||
// strength against preimage attacks of x bits. Since they only produce "x"
|
||||
// bits of output, their collision-resistance is only "x/2" bits.
|
||||
//
|
||||
// The SHAKE-256 and -128 functions have a generic security strength of 256 and
|
||||
// 128 bits against all attacks, provided that at least 2x bits of their output
|
||||
// is used. Requesting more than 64 or 32 bytes of output, respectively, does
|
||||
// not increase the collision-resistance of the SHAKE functions.
|
||||
//
|
||||
// # The sponge construction
|
||||
//
|
||||
// A sponge builds a pseudo-random function from a public pseudo-random
|
||||
// permutation, by applying the permutation to a state of "rate + capacity"
|
||||
// bytes, but hiding "capacity" of the bytes.
|
||||
//
|
||||
// A sponge starts out with a zero state. To hash an input using a sponge, up
|
||||
// to "rate" bytes of the input are XORed into the sponge's state. The sponge
|
||||
// is then "full" and the permutation is applied to "empty" it. This process is
|
||||
// repeated until all the input has been "absorbed". The input is then padded.
|
||||
// The digest is "squeezed" from the sponge in the same way, except that output
|
||||
// is copied out instead of input being XORed in.
|
||||
//
|
||||
// A sponge is parameterized by its generic security strength, which is equal
|
||||
// to half its capacity; capacity + rate is equal to the permutation's width.
|
||||
// Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means
|
||||
// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2.
|
||||
//
|
||||
// # Recommendations
|
||||
//
|
||||
// The SHAKE functions are recommended for most new uses. They can produce
|
||||
// output of arbitrary length. SHAKE256, with an output length of at least
|
||||
// 64 bytes, provides 256-bit security against all attacks. The Keccak team
|
||||
// recommends it for most applications upgrading from SHA2-512. (NIST chose a
|
||||
// much stronger, but much slower, sponge instance for SHA3-512.)
|
||||
//
|
||||
// The SHA-3 functions are "drop-in" replacements for the SHA-2 functions.
|
||||
// They produce output of the same length, with the same security strengths
|
||||
// against all attacks. This means, in particular, that SHA3-256 only has
|
||||
// 128-bit collision resistance, because its output length is 32 bytes.
|
||||
package sha3 // import "golang.org/x/crypto/sha3"
|
97
vendor/golang.org/x/crypto/sha3/hashes.go
generated
vendored
Normal file
97
vendor/golang.org/x/crypto/sha3/hashes.go
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
// Copyright 2014 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 sha3
|
||||
|
||||
// This file provides functions for creating instances of the SHA-3
|
||||
// and SHAKE hash functions, as well as utility functions for hashing
|
||||
// bytes.
|
||||
|
||||
import (
|
||||
"hash"
|
||||
)
|
||||
|
||||
// New224 creates a new SHA3-224 hash.
|
||||
// Its generic security strength is 224 bits against preimage attacks,
|
||||
// and 112 bits against collision attacks.
|
||||
func New224() hash.Hash {
|
||||
if h := new224Asm(); h != nil {
|
||||
return h
|
||||
}
|
||||
return &state{rate: 144, outputLen: 28, dsbyte: 0x06}
|
||||
}
|
||||
|
||||
// New256 creates a new SHA3-256 hash.
|
||||
// Its generic security strength is 256 bits against preimage attacks,
|
||||
// and 128 bits against collision attacks.
|
||||
func New256() hash.Hash {
|
||||
if h := new256Asm(); h != nil {
|
||||
return h
|
||||
}
|
||||
return &state{rate: 136, outputLen: 32, dsbyte: 0x06}
|
||||
}
|
||||
|
||||
// New384 creates a new SHA3-384 hash.
|
||||
// Its generic security strength is 384 bits against preimage attacks,
|
||||
// and 192 bits against collision attacks.
|
||||
func New384() hash.Hash {
|
||||
if h := new384Asm(); h != nil {
|
||||
return h
|
||||
}
|
||||
return &state{rate: 104, outputLen: 48, dsbyte: 0x06}
|
||||
}
|
||||
|
||||
// New512 creates a new SHA3-512 hash.
|
||||
// Its generic security strength is 512 bits against preimage attacks,
|
||||
// and 256 bits against collision attacks.
|
||||
func New512() hash.Hash {
|
||||
if h := new512Asm(); h != nil {
|
||||
return h
|
||||
}
|
||||
return &state{rate: 72, outputLen: 64, dsbyte: 0x06}
|
||||
}
|
||||
|
||||
// NewLegacyKeccak256 creates a new Keccak-256 hash.
|
||||
//
|
||||
// Only use this function if you require compatibility with an existing cryptosystem
|
||||
// that uses non-standard padding. All other users should use New256 instead.
|
||||
func NewLegacyKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} }
|
||||
|
||||
// NewLegacyKeccak512 creates a new Keccak-512 hash.
|
||||
//
|
||||
// Only use this function if you require compatibility with an existing cryptosystem
|
||||
// that uses non-standard padding. All other users should use New512 instead.
|
||||
func NewLegacyKeccak512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x01} }
|
||||
|
||||
// Sum224 returns the SHA3-224 digest of the data.
|
||||
func Sum224(data []byte) (digest [28]byte) {
|
||||
h := New224()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
}
|
||||
|
||||
// Sum256 returns the SHA3-256 digest of the data.
|
||||
func Sum256(data []byte) (digest [32]byte) {
|
||||
h := New256()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
}
|
||||
|
||||
// Sum384 returns the SHA3-384 digest of the data.
|
||||
func Sum384(data []byte) (digest [48]byte) {
|
||||
h := New384()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
}
|
||||
|
||||
// Sum512 returns the SHA3-512 digest of the data.
|
||||
func Sum512(data []byte) (digest [64]byte) {
|
||||
h := New512()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
}
|
28
vendor/golang.org/x/crypto/sha3/hashes_generic.go
generated
vendored
Normal file
28
vendor/golang.org/x/crypto/sha3/hashes_generic.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
//go:build !gc || purego || !s390x
|
||||
// +build !gc purego !s390x
|
||||
|
||||
package sha3
|
||||
|
||||
import (
|
||||
"hash"
|
||||
)
|
||||
|
||||
// new224Asm returns an assembly implementation of SHA3-224 if available,
|
||||
// otherwise it returns nil.
|
||||
func new224Asm() hash.Hash { return nil }
|
||||
|
||||
// new256Asm returns an assembly implementation of SHA3-256 if available,
|
||||
// otherwise it returns nil.
|
||||
func new256Asm() hash.Hash { return nil }
|
||||
|
||||
// new384Asm returns an assembly implementation of SHA3-384 if available,
|
||||
// otherwise it returns nil.
|
||||
func new384Asm() hash.Hash { return nil }
|
||||
|
||||
// new512Asm returns an assembly implementation of SHA3-512 if available,
|
||||
// otherwise it returns nil.
|
||||
func new512Asm() hash.Hash { return nil }
|
415
vendor/golang.org/x/crypto/sha3/keccakf.go
generated
vendored
Normal file
415
vendor/golang.org/x/crypto/sha3/keccakf.go
generated
vendored
Normal file
@ -0,0 +1,415 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
//go:build !amd64 || purego || !gc
|
||||
// +build !amd64 purego !gc
|
||||
|
||||
package sha3
|
||||
|
||||
import "math/bits"
|
||||
|
||||
// rc stores the round constants for use in the ι step.
|
||||
var rc = [24]uint64{
|
||||
0x0000000000000001,
|
||||
0x0000000000008082,
|
||||
0x800000000000808A,
|
||||
0x8000000080008000,
|
||||
0x000000000000808B,
|
||||
0x0000000080000001,
|
||||
0x8000000080008081,
|
||||
0x8000000000008009,
|
||||
0x000000000000008A,
|
||||
0x0000000000000088,
|
||||
0x0000000080008009,
|
||||
0x000000008000000A,
|
||||
0x000000008000808B,
|
||||
0x800000000000008B,
|
||||
0x8000000000008089,
|
||||
0x8000000000008003,
|
||||
0x8000000000008002,
|
||||
0x8000000000000080,
|
||||
0x000000000000800A,
|
||||
0x800000008000000A,
|
||||
0x8000000080008081,
|
||||
0x8000000000008080,
|
||||
0x0000000080000001,
|
||||
0x8000000080008008,
|
||||
}
|
||||
|
||||
// keccakF1600 applies the Keccak permutation to a 1600b-wide
|
||||
// state represented as a slice of 25 uint64s.
|
||||
func keccakF1600(a *[25]uint64) {
|
||||
// Implementation translated from Keccak-inplace.c
|
||||
// in the keccak reference code.
|
||||
var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64
|
||||
|
||||
for i := 0; i < 24; i += 4 {
|
||||
// Combines the 5 steps in each round into 2 steps.
|
||||
// Unrolls 4 rounds per loop and spreads some steps across rounds.
|
||||
|
||||
// Round 1
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[6] ^ d1
|
||||
bc1 = bits.RotateLeft64(t, 44)
|
||||
t = a[12] ^ d2
|
||||
bc2 = bits.RotateLeft64(t, 43)
|
||||
t = a[18] ^ d3
|
||||
bc3 = bits.RotateLeft64(t, 21)
|
||||
t = a[24] ^ d4
|
||||
bc4 = bits.RotateLeft64(t, 14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i]
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc2 = bits.RotateLeft64(t, 3)
|
||||
t = a[16] ^ d1
|
||||
bc3 = bits.RotateLeft64(t, 45)
|
||||
t = a[22] ^ d2
|
||||
bc4 = bits.RotateLeft64(t, 61)
|
||||
t = a[3] ^ d3
|
||||
bc0 = bits.RotateLeft64(t, 28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = bits.RotateLeft64(t, 20)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc4 = bits.RotateLeft64(t, 18)
|
||||
t = a[1] ^ d1
|
||||
bc0 = bits.RotateLeft64(t, 1)
|
||||
t = a[7] ^ d2
|
||||
bc1 = bits.RotateLeft64(t, 6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = bits.RotateLeft64(t, 25)
|
||||
t = a[19] ^ d4
|
||||
bc3 = bits.RotateLeft64(t, 8)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc1 = bits.RotateLeft64(t, 36)
|
||||
t = a[11] ^ d1
|
||||
bc2 = bits.RotateLeft64(t, 10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = bits.RotateLeft64(t, 15)
|
||||
t = a[23] ^ d3
|
||||
bc4 = bits.RotateLeft64(t, 56)
|
||||
t = a[4] ^ d4
|
||||
bc0 = bits.RotateLeft64(t, 27)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc3 = bits.RotateLeft64(t, 41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = bits.RotateLeft64(t, 2)
|
||||
t = a[2] ^ d2
|
||||
bc0 = bits.RotateLeft64(t, 62)
|
||||
t = a[8] ^ d3
|
||||
bc1 = bits.RotateLeft64(t, 55)
|
||||
t = a[14] ^ d4
|
||||
bc2 = bits.RotateLeft64(t, 39)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
// Round 2
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[16] ^ d1
|
||||
bc1 = bits.RotateLeft64(t, 44)
|
||||
t = a[7] ^ d2
|
||||
bc2 = bits.RotateLeft64(t, 43)
|
||||
t = a[23] ^ d3
|
||||
bc3 = bits.RotateLeft64(t, 21)
|
||||
t = a[14] ^ d4
|
||||
bc4 = bits.RotateLeft64(t, 14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+1]
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc2 = bits.RotateLeft64(t, 3)
|
||||
t = a[11] ^ d1
|
||||
bc3 = bits.RotateLeft64(t, 45)
|
||||
t = a[2] ^ d2
|
||||
bc4 = bits.RotateLeft64(t, 61)
|
||||
t = a[18] ^ d3
|
||||
bc0 = bits.RotateLeft64(t, 28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = bits.RotateLeft64(t, 20)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc4 = bits.RotateLeft64(t, 18)
|
||||
t = a[6] ^ d1
|
||||
bc0 = bits.RotateLeft64(t, 1)
|
||||
t = a[22] ^ d2
|
||||
bc1 = bits.RotateLeft64(t, 6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = bits.RotateLeft64(t, 25)
|
||||
t = a[4] ^ d4
|
||||
bc3 = bits.RotateLeft64(t, 8)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc1 = bits.RotateLeft64(t, 36)
|
||||
t = a[1] ^ d1
|
||||
bc2 = bits.RotateLeft64(t, 10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = bits.RotateLeft64(t, 15)
|
||||
t = a[8] ^ d3
|
||||
bc4 = bits.RotateLeft64(t, 56)
|
||||
t = a[24] ^ d4
|
||||
bc0 = bits.RotateLeft64(t, 27)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc3 = bits.RotateLeft64(t, 41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = bits.RotateLeft64(t, 2)
|
||||
t = a[12] ^ d2
|
||||
bc0 = bits.RotateLeft64(t, 62)
|
||||
t = a[3] ^ d3
|
||||
bc1 = bits.RotateLeft64(t, 55)
|
||||
t = a[19] ^ d4
|
||||
bc2 = bits.RotateLeft64(t, 39)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
// Round 3
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[11] ^ d1
|
||||
bc1 = bits.RotateLeft64(t, 44)
|
||||
t = a[22] ^ d2
|
||||
bc2 = bits.RotateLeft64(t, 43)
|
||||
t = a[8] ^ d3
|
||||
bc3 = bits.RotateLeft64(t, 21)
|
||||
t = a[19] ^ d4
|
||||
bc4 = bits.RotateLeft64(t, 14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+2]
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc2 = bits.RotateLeft64(t, 3)
|
||||
t = a[1] ^ d1
|
||||
bc3 = bits.RotateLeft64(t, 45)
|
||||
t = a[12] ^ d2
|
||||
bc4 = bits.RotateLeft64(t, 61)
|
||||
t = a[23] ^ d3
|
||||
bc0 = bits.RotateLeft64(t, 28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = bits.RotateLeft64(t, 20)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc4 = bits.RotateLeft64(t, 18)
|
||||
t = a[16] ^ d1
|
||||
bc0 = bits.RotateLeft64(t, 1)
|
||||
t = a[2] ^ d2
|
||||
bc1 = bits.RotateLeft64(t, 6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = bits.RotateLeft64(t, 25)
|
||||
t = a[24] ^ d4
|
||||
bc3 = bits.RotateLeft64(t, 8)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc1 = bits.RotateLeft64(t, 36)
|
||||
t = a[6] ^ d1
|
||||
bc2 = bits.RotateLeft64(t, 10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = bits.RotateLeft64(t, 15)
|
||||
t = a[3] ^ d3
|
||||
bc4 = bits.RotateLeft64(t, 56)
|
||||
t = a[14] ^ d4
|
||||
bc0 = bits.RotateLeft64(t, 27)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc3 = bits.RotateLeft64(t, 41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = bits.RotateLeft64(t, 2)
|
||||
t = a[7] ^ d2
|
||||
bc0 = bits.RotateLeft64(t, 62)
|
||||
t = a[18] ^ d3
|
||||
bc1 = bits.RotateLeft64(t, 55)
|
||||
t = a[4] ^ d4
|
||||
bc2 = bits.RotateLeft64(t, 39)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
// Round 4
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[1] ^ d1
|
||||
bc1 = bits.RotateLeft64(t, 44)
|
||||
t = a[2] ^ d2
|
||||
bc2 = bits.RotateLeft64(t, 43)
|
||||
t = a[3] ^ d3
|
||||
bc3 = bits.RotateLeft64(t, 21)
|
||||
t = a[4] ^ d4
|
||||
bc4 = bits.RotateLeft64(t, 14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+3]
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc2 = bits.RotateLeft64(t, 3)
|
||||
t = a[6] ^ d1
|
||||
bc3 = bits.RotateLeft64(t, 45)
|
||||
t = a[7] ^ d2
|
||||
bc4 = bits.RotateLeft64(t, 61)
|
||||
t = a[8] ^ d3
|
||||
bc0 = bits.RotateLeft64(t, 28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = bits.RotateLeft64(t, 20)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc4 = bits.RotateLeft64(t, 18)
|
||||
t = a[11] ^ d1
|
||||
bc0 = bits.RotateLeft64(t, 1)
|
||||
t = a[12] ^ d2
|
||||
bc1 = bits.RotateLeft64(t, 6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = bits.RotateLeft64(t, 25)
|
||||
t = a[14] ^ d4
|
||||
bc3 = bits.RotateLeft64(t, 8)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc1 = bits.RotateLeft64(t, 36)
|
||||
t = a[16] ^ d1
|
||||
bc2 = bits.RotateLeft64(t, 10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = bits.RotateLeft64(t, 15)
|
||||
t = a[18] ^ d3
|
||||
bc4 = bits.RotateLeft64(t, 56)
|
||||
t = a[19] ^ d4
|
||||
bc0 = bits.RotateLeft64(t, 27)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc3 = bits.RotateLeft64(t, 41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = bits.RotateLeft64(t, 2)
|
||||
t = a[22] ^ d2
|
||||
bc0 = bits.RotateLeft64(t, 62)
|
||||
t = a[23] ^ d3
|
||||
bc1 = bits.RotateLeft64(t, 55)
|
||||
t = a[24] ^ d4
|
||||
bc2 = bits.RotateLeft64(t, 39)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
}
|
||||
}
|
14
vendor/golang.org/x/crypto/sha3/keccakf_amd64.go
generated
vendored
Normal file
14
vendor/golang.org/x/crypto/sha3/keccakf_amd64.go
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
//go:build amd64 && !purego && gc
|
||||
// +build amd64,!purego,gc
|
||||
|
||||
package sha3
|
||||
|
||||
// This function is implemented in keccakf_amd64.s.
|
||||
|
||||
//go:noescape
|
||||
|
||||
func keccakF1600(a *[25]uint64)
|
391
vendor/golang.org/x/crypto/sha3/keccakf_amd64.s
generated
vendored
Normal file
391
vendor/golang.org/x/crypto/sha3/keccakf_amd64.s
generated
vendored
Normal file
@ -0,0 +1,391 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
//go:build amd64 && !purego && gc
|
||||
// +build amd64,!purego,gc
|
||||
|
||||
// This code was translated into a form compatible with 6a from the public
|
||||
// domain sources at https://github.com/gvanas/KeccakCodePackage
|
||||
|
||||
// Offsets in state
|
||||
#define _ba (0*8)
|
||||
#define _be (1*8)
|
||||
#define _bi (2*8)
|
||||
#define _bo (3*8)
|
||||
#define _bu (4*8)
|
||||
#define _ga (5*8)
|
||||
#define _ge (6*8)
|
||||
#define _gi (7*8)
|
||||
#define _go (8*8)
|
||||
#define _gu (9*8)
|
||||
#define _ka (10*8)
|
||||
#define _ke (11*8)
|
||||
#define _ki (12*8)
|
||||
#define _ko (13*8)
|
||||
#define _ku (14*8)
|
||||
#define _ma (15*8)
|
||||
#define _me (16*8)
|
||||
#define _mi (17*8)
|
||||
#define _mo (18*8)
|
||||
#define _mu (19*8)
|
||||
#define _sa (20*8)
|
||||
#define _se (21*8)
|
||||
#define _si (22*8)
|
||||
#define _so (23*8)
|
||||
#define _su (24*8)
|
||||
|
||||
// Temporary registers
|
||||
#define rT1 AX
|
||||
|
||||
// Round vars
|
||||
#define rpState DI
|
||||
#define rpStack SP
|
||||
|
||||
#define rDa BX
|
||||
#define rDe CX
|
||||
#define rDi DX
|
||||
#define rDo R8
|
||||
#define rDu R9
|
||||
|
||||
#define rBa R10
|
||||
#define rBe R11
|
||||
#define rBi R12
|
||||
#define rBo R13
|
||||
#define rBu R14
|
||||
|
||||
#define rCa SI
|
||||
#define rCe BP
|
||||
#define rCi rBi
|
||||
#define rCo rBo
|
||||
#define rCu R15
|
||||
|
||||
#define MOVQ_RBI_RCE MOVQ rBi, rCe
|
||||
#define XORQ_RT1_RCA XORQ rT1, rCa
|
||||
#define XORQ_RT1_RCE XORQ rT1, rCe
|
||||
#define XORQ_RBA_RCU XORQ rBa, rCu
|
||||
#define XORQ_RBE_RCU XORQ rBe, rCu
|
||||
#define XORQ_RDU_RCU XORQ rDu, rCu
|
||||
#define XORQ_RDA_RCA XORQ rDa, rCa
|
||||
#define XORQ_RDE_RCE XORQ rDe, rCe
|
||||
|
||||
#define mKeccakRound(iState, oState, rc, B_RBI_RCE, G_RT1_RCA, G_RT1_RCE, G_RBA_RCU, K_RT1_RCA, K_RT1_RCE, K_RBA_RCU, M_RT1_RCA, M_RT1_RCE, M_RBE_RCU, S_RDU_RCU, S_RDA_RCA, S_RDE_RCE) \
|
||||
/* Prepare round */ \
|
||||
MOVQ rCe, rDa; \
|
||||
ROLQ $1, rDa; \
|
||||
\
|
||||
MOVQ _bi(iState), rCi; \
|
||||
XORQ _gi(iState), rDi; \
|
||||
XORQ rCu, rDa; \
|
||||
XORQ _ki(iState), rCi; \
|
||||
XORQ _mi(iState), rDi; \
|
||||
XORQ rDi, rCi; \
|
||||
\
|
||||
MOVQ rCi, rDe; \
|
||||
ROLQ $1, rDe; \
|
||||
\
|
||||
MOVQ _bo(iState), rCo; \
|
||||
XORQ _go(iState), rDo; \
|
||||
XORQ rCa, rDe; \
|
||||
XORQ _ko(iState), rCo; \
|
||||
XORQ _mo(iState), rDo; \
|
||||
XORQ rDo, rCo; \
|
||||
\
|
||||
MOVQ rCo, rDi; \
|
||||
ROLQ $1, rDi; \
|
||||
\
|
||||
MOVQ rCu, rDo; \
|
||||
XORQ rCe, rDi; \
|
||||
ROLQ $1, rDo; \
|
||||
\
|
||||
MOVQ rCa, rDu; \
|
||||
XORQ rCi, rDo; \
|
||||
ROLQ $1, rDu; \
|
||||
\
|
||||
/* Result b */ \
|
||||
MOVQ _ba(iState), rBa; \
|
||||
MOVQ _ge(iState), rBe; \
|
||||
XORQ rCo, rDu; \
|
||||
MOVQ _ki(iState), rBi; \
|
||||
MOVQ _mo(iState), rBo; \
|
||||
MOVQ _su(iState), rBu; \
|
||||
XORQ rDe, rBe; \
|
||||
ROLQ $44, rBe; \
|
||||
XORQ rDi, rBi; \
|
||||
XORQ rDa, rBa; \
|
||||
ROLQ $43, rBi; \
|
||||
\
|
||||
MOVQ rBe, rCa; \
|
||||
MOVQ rc, rT1; \
|
||||
ORQ rBi, rCa; \
|
||||
XORQ rBa, rT1; \
|
||||
XORQ rT1, rCa; \
|
||||
MOVQ rCa, _ba(oState); \
|
||||
\
|
||||
XORQ rDu, rBu; \
|
||||
ROLQ $14, rBu; \
|
||||
MOVQ rBa, rCu; \
|
||||
ANDQ rBe, rCu; \
|
||||
XORQ rBu, rCu; \
|
||||
MOVQ rCu, _bu(oState); \
|
||||
\
|
||||
XORQ rDo, rBo; \
|
||||
ROLQ $21, rBo; \
|
||||
MOVQ rBo, rT1; \
|
||||
ANDQ rBu, rT1; \
|
||||
XORQ rBi, rT1; \
|
||||
MOVQ rT1, _bi(oState); \
|
||||
\
|
||||
NOTQ rBi; \
|
||||
ORQ rBa, rBu; \
|
||||
ORQ rBo, rBi; \
|
||||
XORQ rBo, rBu; \
|
||||
XORQ rBe, rBi; \
|
||||
MOVQ rBu, _bo(oState); \
|
||||
MOVQ rBi, _be(oState); \
|
||||
B_RBI_RCE; \
|
||||
\
|
||||
/* Result g */ \
|
||||
MOVQ _gu(iState), rBe; \
|
||||
XORQ rDu, rBe; \
|
||||
MOVQ _ka(iState), rBi; \
|
||||
ROLQ $20, rBe; \
|
||||
XORQ rDa, rBi; \
|
||||
ROLQ $3, rBi; \
|
||||
MOVQ _bo(iState), rBa; \
|
||||
MOVQ rBe, rT1; \
|
||||
ORQ rBi, rT1; \
|
||||
XORQ rDo, rBa; \
|
||||
MOVQ _me(iState), rBo; \
|
||||
MOVQ _si(iState), rBu; \
|
||||
ROLQ $28, rBa; \
|
||||
XORQ rBa, rT1; \
|
||||
MOVQ rT1, _ga(oState); \
|
||||
G_RT1_RCA; \
|
||||
\
|
||||
XORQ rDe, rBo; \
|
||||
ROLQ $45, rBo; \
|
||||
MOVQ rBi, rT1; \
|
||||
ANDQ rBo, rT1; \
|
||||
XORQ rBe, rT1; \
|
||||
MOVQ rT1, _ge(oState); \
|
||||
G_RT1_RCE; \
|
||||
\
|
||||
XORQ rDi, rBu; \
|
||||
ROLQ $61, rBu; \
|
||||
MOVQ rBu, rT1; \
|
||||
ORQ rBa, rT1; \
|
||||
XORQ rBo, rT1; \
|
||||
MOVQ rT1, _go(oState); \
|
||||
\
|
||||
ANDQ rBe, rBa; \
|
||||
XORQ rBu, rBa; \
|
||||
MOVQ rBa, _gu(oState); \
|
||||
NOTQ rBu; \
|
||||
G_RBA_RCU; \
|
||||
\
|
||||
ORQ rBu, rBo; \
|
||||
XORQ rBi, rBo; \
|
||||
MOVQ rBo, _gi(oState); \
|
||||
\
|
||||
/* Result k */ \
|
||||
MOVQ _be(iState), rBa; \
|
||||
MOVQ _gi(iState), rBe; \
|
||||
MOVQ _ko(iState), rBi; \
|
||||
MOVQ _mu(iState), rBo; \
|
||||
MOVQ _sa(iState), rBu; \
|
||||
XORQ rDi, rBe; \
|
||||
ROLQ $6, rBe; \
|
||||
XORQ rDo, rBi; \
|
||||
ROLQ $25, rBi; \
|
||||
MOVQ rBe, rT1; \
|
||||
ORQ rBi, rT1; \
|
||||
XORQ rDe, rBa; \
|
||||
ROLQ $1, rBa; \
|
||||
XORQ rBa, rT1; \
|
||||
MOVQ rT1, _ka(oState); \
|
||||
K_RT1_RCA; \
|
||||
\
|
||||
XORQ rDu, rBo; \
|
||||
ROLQ $8, rBo; \
|
||||
MOVQ rBi, rT1; \
|
||||
ANDQ rBo, rT1; \
|
||||
XORQ rBe, rT1; \
|
||||
MOVQ rT1, _ke(oState); \
|
||||
K_RT1_RCE; \
|
||||
\
|
||||
XORQ rDa, rBu; \
|
||||
ROLQ $18, rBu; \
|
||||
NOTQ rBo; \
|
||||
MOVQ rBo, rT1; \
|
||||
ANDQ rBu, rT1; \
|
||||
XORQ rBi, rT1; \
|
||||
MOVQ rT1, _ki(oState); \
|
||||
\
|
||||
MOVQ rBu, rT1; \
|
||||
ORQ rBa, rT1; \
|
||||
XORQ rBo, rT1; \
|
||||
MOVQ rT1, _ko(oState); \
|
||||
\
|
||||
ANDQ rBe, rBa; \
|
||||
XORQ rBu, rBa; \
|
||||
MOVQ rBa, _ku(oState); \
|
||||
K_RBA_RCU; \
|
||||
\
|
||||
/* Result m */ \
|
||||
MOVQ _ga(iState), rBe; \
|
||||
XORQ rDa, rBe; \
|
||||
MOVQ _ke(iState), rBi; \
|
||||
ROLQ $36, rBe; \
|
||||
XORQ rDe, rBi; \
|
||||
MOVQ _bu(iState), rBa; \
|
||||
ROLQ $10, rBi; \
|
||||
MOVQ rBe, rT1; \
|
||||
MOVQ _mi(iState), rBo; \
|
||||
ANDQ rBi, rT1; \
|
||||
XORQ rDu, rBa; \
|
||||
MOVQ _so(iState), rBu; \
|
||||
ROLQ $27, rBa; \
|
||||
XORQ rBa, rT1; \
|
||||
MOVQ rT1, _ma(oState); \
|
||||
M_RT1_RCA; \
|
||||
\
|
||||
XORQ rDi, rBo; \
|
||||
ROLQ $15, rBo; \
|
||||
MOVQ rBi, rT1; \
|
||||
ORQ rBo, rT1; \
|
||||
XORQ rBe, rT1; \
|
||||
MOVQ rT1, _me(oState); \
|
||||
M_RT1_RCE; \
|
||||
\
|
||||
XORQ rDo, rBu; \
|
||||
ROLQ $56, rBu; \
|
||||
NOTQ rBo; \
|
||||
MOVQ rBo, rT1; \
|
||||
ORQ rBu, rT1; \
|
||||
XORQ rBi, rT1; \
|
||||
MOVQ rT1, _mi(oState); \
|
||||
\
|
||||
ORQ rBa, rBe; \
|
||||
XORQ rBu, rBe; \
|
||||
MOVQ rBe, _mu(oState); \
|
||||
\
|
||||
ANDQ rBa, rBu; \
|
||||
XORQ rBo, rBu; \
|
||||
MOVQ rBu, _mo(oState); \
|
||||
M_RBE_RCU; \
|
||||
\
|
||||
/* Result s */ \
|
||||
MOVQ _bi(iState), rBa; \
|
||||
MOVQ _go(iState), rBe; \
|
||||
MOVQ _ku(iState), rBi; \
|
||||
XORQ rDi, rBa; \
|
||||
MOVQ _ma(iState), rBo; \
|
||||
ROLQ $62, rBa; \
|
||||
XORQ rDo, rBe; \
|
||||
MOVQ _se(iState), rBu; \
|
||||
ROLQ $55, rBe; \
|
||||
\
|
||||
XORQ rDu, rBi; \
|
||||
MOVQ rBa, rDu; \
|
||||
XORQ rDe, rBu; \
|
||||
ROLQ $2, rBu; \
|
||||
ANDQ rBe, rDu; \
|
||||
XORQ rBu, rDu; \
|
||||
MOVQ rDu, _su(oState); \
|
||||
\
|
||||
ROLQ $39, rBi; \
|
||||
S_RDU_RCU; \
|
||||
NOTQ rBe; \
|
||||
XORQ rDa, rBo; \
|
||||
MOVQ rBe, rDa; \
|
||||
ANDQ rBi, rDa; \
|
||||
XORQ rBa, rDa; \
|
||||
MOVQ rDa, _sa(oState); \
|
||||
S_RDA_RCA; \
|
||||
\
|
||||
ROLQ $41, rBo; \
|
||||
MOVQ rBi, rDe; \
|
||||
ORQ rBo, rDe; \
|
||||
XORQ rBe, rDe; \
|
||||
MOVQ rDe, _se(oState); \
|
||||
S_RDE_RCE; \
|
||||
\
|
||||
MOVQ rBo, rDi; \
|
||||
MOVQ rBu, rDo; \
|
||||
ANDQ rBu, rDi; \
|
||||
ORQ rBa, rDo; \
|
||||
XORQ rBi, rDi; \
|
||||
XORQ rBo, rDo; \
|
||||
MOVQ rDi, _si(oState); \
|
||||
MOVQ rDo, _so(oState) \
|
||||
|
||||
// func keccakF1600(state *[25]uint64)
|
||||
TEXT ·keccakF1600(SB), 0, $200-8
|
||||
MOVQ state+0(FP), rpState
|
||||
|
||||
// Convert the user state into an internal state
|
||||
NOTQ _be(rpState)
|
||||
NOTQ _bi(rpState)
|
||||
NOTQ _go(rpState)
|
||||
NOTQ _ki(rpState)
|
||||
NOTQ _mi(rpState)
|
||||
NOTQ _sa(rpState)
|
||||
|
||||
// Execute the KeccakF permutation
|
||||
MOVQ _ba(rpState), rCa
|
||||
MOVQ _be(rpState), rCe
|
||||
MOVQ _bu(rpState), rCu
|
||||
|
||||
XORQ _ga(rpState), rCa
|
||||
XORQ _ge(rpState), rCe
|
||||
XORQ _gu(rpState), rCu
|
||||
|
||||
XORQ _ka(rpState), rCa
|
||||
XORQ _ke(rpState), rCe
|
||||
XORQ _ku(rpState), rCu
|
||||
|
||||
XORQ _ma(rpState), rCa
|
||||
XORQ _me(rpState), rCe
|
||||
XORQ _mu(rpState), rCu
|
||||
|
||||
XORQ _sa(rpState), rCa
|
||||
XORQ _se(rpState), rCe
|
||||
MOVQ _si(rpState), rDi
|
||||
MOVQ _so(rpState), rDo
|
||||
XORQ _su(rpState), rCu
|
||||
|
||||
mKeccakRound(rpState, rpStack, $0x0000000000000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x0000000000008082, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x800000000000808a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x8000000080008000, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x000000000000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x8000000000008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x000000000000008a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x0000000000000088, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x0000000080008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x000000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x000000008000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x800000000000008b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x8000000000008089, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x8000000000008003, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x8000000000008002, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x8000000000000080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x000000000000800a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x800000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x8000000000008080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x8000000080008008, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP)
|
||||
|
||||
// Revert the internal state to the user state
|
||||
NOTQ _be(rpState)
|
||||
NOTQ _bi(rpState)
|
||||
NOTQ _go(rpState)
|
||||
NOTQ _ki(rpState)
|
||||
NOTQ _mi(rpState)
|
||||
NOTQ _sa(rpState)
|
||||
|
||||
RET
|
19
vendor/golang.org/x/crypto/sha3/register.go
generated
vendored
Normal file
19
vendor/golang.org/x/crypto/sha3/register.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
//go:build go1.4
|
||||
// +build go1.4
|
||||
|
||||
package sha3
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
)
|
||||
|
||||
func init() {
|
||||
crypto.RegisterHash(crypto.SHA3_224, New224)
|
||||
crypto.RegisterHash(crypto.SHA3_256, New256)
|
||||
crypto.RegisterHash(crypto.SHA3_384, New384)
|
||||
crypto.RegisterHash(crypto.SHA3_512, New512)
|
||||
}
|
193
vendor/golang.org/x/crypto/sha3/sha3.go
generated
vendored
Normal file
193
vendor/golang.org/x/crypto/sha3/sha3.go
generated
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
// Copyright 2014 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 sha3
|
||||
|
||||
// spongeDirection indicates the direction bytes are flowing through the sponge.
|
||||
type spongeDirection int
|
||||
|
||||
const (
|
||||
// spongeAbsorbing indicates that the sponge is absorbing input.
|
||||
spongeAbsorbing spongeDirection = iota
|
||||
// spongeSqueezing indicates that the sponge is being squeezed.
|
||||
spongeSqueezing
|
||||
)
|
||||
|
||||
const (
|
||||
// maxRate is the maximum size of the internal buffer. SHAKE-256
|
||||
// currently needs the largest buffer.
|
||||
maxRate = 168
|
||||
)
|
||||
|
||||
type state struct {
|
||||
// Generic sponge components.
|
||||
a [25]uint64 // main state of the hash
|
||||
buf []byte // points into storage
|
||||
rate int // the number of bytes of state to use
|
||||
|
||||
// dsbyte contains the "domain separation" bits and the first bit of
|
||||
// the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the
|
||||
// SHA-3 and SHAKE functions by appending bitstrings to the message.
|
||||
// Using a little-endian bit-ordering convention, these are "01" for SHA-3
|
||||
// and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the
|
||||
// padding rule from section 5.1 is applied to pad the message to a multiple
|
||||
// of the rate, which involves adding a "1" bit, zero or more "0" bits, and
|
||||
// a final "1" bit. We merge the first "1" bit from the padding into dsbyte,
|
||||
// giving 00000110b (0x06) and 00011111b (0x1f).
|
||||
// [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf
|
||||
// "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and
|
||||
// Extendable-Output Functions (May 2014)"
|
||||
dsbyte byte
|
||||
|
||||
storage storageBuf
|
||||
|
||||
// Specific to SHA-3 and SHAKE.
|
||||
outputLen int // the default output size in bytes
|
||||
state spongeDirection // whether the sponge is absorbing or squeezing
|
||||
}
|
||||
|
||||
// BlockSize returns the rate of sponge underlying this hash function.
|
||||
func (d *state) BlockSize() int { return d.rate }
|
||||
|
||||
// Size returns the output size of the hash function in bytes.
|
||||
func (d *state) Size() int { return d.outputLen }
|
||||
|
||||
// Reset clears the internal state by zeroing the sponge state and
|
||||
// the byte buffer, and setting Sponge.state to absorbing.
|
||||
func (d *state) Reset() {
|
||||
// Zero the permutation's state.
|
||||
for i := range d.a {
|
||||
d.a[i] = 0
|
||||
}
|
||||
d.state = spongeAbsorbing
|
||||
d.buf = d.storage.asBytes()[:0]
|
||||
}
|
||||
|
||||
func (d *state) clone() *state {
|
||||
ret := *d
|
||||
if ret.state == spongeAbsorbing {
|
||||
ret.buf = ret.storage.asBytes()[:len(ret.buf)]
|
||||
} else {
|
||||
ret.buf = ret.storage.asBytes()[d.rate-cap(d.buf) : d.rate]
|
||||
}
|
||||
|
||||
return &ret
|
||||
}
|
||||
|
||||
// permute applies the KeccakF-1600 permutation. It handles
|
||||
// any input-output buffering.
|
||||
func (d *state) permute() {
|
||||
switch d.state {
|
||||
case spongeAbsorbing:
|
||||
// If we're absorbing, we need to xor the input into the state
|
||||
// before applying the permutation.
|
||||
xorIn(d, d.buf)
|
||||
d.buf = d.storage.asBytes()[:0]
|
||||
keccakF1600(&d.a)
|
||||
case spongeSqueezing:
|
||||
// If we're squeezing, we need to apply the permutation before
|
||||
// copying more output.
|
||||
keccakF1600(&d.a)
|
||||
d.buf = d.storage.asBytes()[:d.rate]
|
||||
copyOut(d, d.buf)
|
||||
}
|
||||
}
|
||||
|
||||
// pads appends the domain separation bits in dsbyte, applies
|
||||
// the multi-bitrate 10..1 padding rule, and permutes the state.
|
||||
func (d *state) padAndPermute(dsbyte byte) {
|
||||
if d.buf == nil {
|
||||
d.buf = d.storage.asBytes()[:0]
|
||||
}
|
||||
// Pad with this instance's domain-separator bits. We know that there's
|
||||
// at least one byte of space in d.buf because, if it were full,
|
||||
// permute would have been called to empty it. dsbyte also contains the
|
||||
// first one bit for the padding. See the comment in the state struct.
|
||||
d.buf = append(d.buf, dsbyte)
|
||||
zerosStart := len(d.buf)
|
||||
d.buf = d.storage.asBytes()[:d.rate]
|
||||
for i := zerosStart; i < d.rate; i++ {
|
||||
d.buf[i] = 0
|
||||
}
|
||||
// This adds the final one bit for the padding. Because of the way that
|
||||
// bits are numbered from the LSB upwards, the final bit is the MSB of
|
||||
// the last byte.
|
||||
d.buf[d.rate-1] ^= 0x80
|
||||
// Apply the permutation
|
||||
d.permute()
|
||||
d.state = spongeSqueezing
|
||||
d.buf = d.storage.asBytes()[:d.rate]
|
||||
copyOut(d, d.buf)
|
||||
}
|
||||
|
||||
// Write absorbs more data into the hash's state. It produces an error
|
||||
// if more data is written to the ShakeHash after writing
|
||||
func (d *state) Write(p []byte) (written int, err error) {
|
||||
if d.state != spongeAbsorbing {
|
||||
panic("sha3: write to sponge after read")
|
||||
}
|
||||
if d.buf == nil {
|
||||
d.buf = d.storage.asBytes()[:0]
|
||||
}
|
||||
written = len(p)
|
||||
|
||||
for len(p) > 0 {
|
||||
if len(d.buf) == 0 && len(p) >= d.rate {
|
||||
// The fast path; absorb a full "rate" bytes of input and apply the permutation.
|
||||
xorIn(d, p[:d.rate])
|
||||
p = p[d.rate:]
|
||||
keccakF1600(&d.a)
|
||||
} else {
|
||||
// The slow path; buffer the input until we can fill the sponge, and then xor it in.
|
||||
todo := d.rate - len(d.buf)
|
||||
if todo > len(p) {
|
||||
todo = len(p)
|
||||
}
|
||||
d.buf = append(d.buf, p[:todo]...)
|
||||
p = p[todo:]
|
||||
|
||||
// If the sponge is full, apply the permutation.
|
||||
if len(d.buf) == d.rate {
|
||||
d.permute()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Read squeezes an arbitrary number of bytes from the sponge.
|
||||
func (d *state) Read(out []byte) (n int, err error) {
|
||||
// If we're still absorbing, pad and apply the permutation.
|
||||
if d.state == spongeAbsorbing {
|
||||
d.padAndPermute(d.dsbyte)
|
||||
}
|
||||
|
||||
n = len(out)
|
||||
|
||||
// Now, do the squeezing.
|
||||
for len(out) > 0 {
|
||||
n := copy(out, d.buf)
|
||||
d.buf = d.buf[n:]
|
||||
out = out[n:]
|
||||
|
||||
// Apply the permutation if we've squeezed the sponge dry.
|
||||
if len(d.buf) == 0 {
|
||||
d.permute()
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Sum applies padding to the hash state and then squeezes out the desired
|
||||
// number of output bytes.
|
||||
func (d *state) Sum(in []byte) []byte {
|
||||
// Make a copy of the original hash so that caller can keep writing
|
||||
// and summing.
|
||||
dup := d.clone()
|
||||
hash := make([]byte, dup.outputLen)
|
||||
dup.Read(hash)
|
||||
return append(in, hash...)
|
||||
}
|
287
vendor/golang.org/x/crypto/sha3/sha3_s390x.go
generated
vendored
Normal file
287
vendor/golang.org/x/crypto/sha3/sha3_s390x.go
generated
vendored
Normal file
@ -0,0 +1,287 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
package sha3
|
||||
|
||||
// This file contains code for using the 'compute intermediate
|
||||
// message digest' (KIMD) and 'compute last message digest' (KLMD)
|
||||
// instructions to compute SHA-3 and SHAKE hashes on IBM Z.
|
||||
|
||||
import (
|
||||
"hash"
|
||||
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
// codes represent 7-bit KIMD/KLMD function codes as defined in
|
||||
// the Principles of Operation.
|
||||
type code uint64
|
||||
|
||||
const (
|
||||
// function codes for KIMD/KLMD
|
||||
sha3_224 code = 32
|
||||
sha3_256 = 33
|
||||
sha3_384 = 34
|
||||
sha3_512 = 35
|
||||
shake_128 = 36
|
||||
shake_256 = 37
|
||||
nopad = 0x100
|
||||
)
|
||||
|
||||
// kimd is a wrapper for the 'compute intermediate message digest' instruction.
|
||||
// src must be a multiple of the rate for the given function code.
|
||||
//
|
||||
//go:noescape
|
||||
func kimd(function code, chain *[200]byte, src []byte)
|
||||
|
||||
// klmd is a wrapper for the 'compute last message digest' instruction.
|
||||
// src padding is handled by the instruction.
|
||||
//
|
||||
//go:noescape
|
||||
func klmd(function code, chain *[200]byte, dst, src []byte)
|
||||
|
||||
type asmState struct {
|
||||
a [200]byte // 1600 bit state
|
||||
buf []byte // care must be taken to ensure cap(buf) is a multiple of rate
|
||||
rate int // equivalent to block size
|
||||
storage [3072]byte // underlying storage for buf
|
||||
outputLen int // output length if fixed, 0 if not
|
||||
function code // KIMD/KLMD function code
|
||||
state spongeDirection // whether the sponge is absorbing or squeezing
|
||||
}
|
||||
|
||||
func newAsmState(function code) *asmState {
|
||||
var s asmState
|
||||
s.function = function
|
||||
switch function {
|
||||
case sha3_224:
|
||||
s.rate = 144
|
||||
s.outputLen = 28
|
||||
case sha3_256:
|
||||
s.rate = 136
|
||||
s.outputLen = 32
|
||||
case sha3_384:
|
||||
s.rate = 104
|
||||
s.outputLen = 48
|
||||
case sha3_512:
|
||||
s.rate = 72
|
||||
s.outputLen = 64
|
||||
case shake_128:
|
||||
s.rate = 168
|
||||
case shake_256:
|
||||
s.rate = 136
|
||||
default:
|
||||
panic("sha3: unrecognized function code")
|
||||
}
|
||||
|
||||
// limit s.buf size to a multiple of s.rate
|
||||
s.resetBuf()
|
||||
return &s
|
||||
}
|
||||
|
||||
func (s *asmState) clone() *asmState {
|
||||
c := *s
|
||||
c.buf = c.storage[:len(s.buf):cap(s.buf)]
|
||||
return &c
|
||||
}
|
||||
|
||||
// copyIntoBuf copies b into buf. It will panic if there is not enough space to
|
||||
// store all of b.
|
||||
func (s *asmState) copyIntoBuf(b []byte) {
|
||||
bufLen := len(s.buf)
|
||||
s.buf = s.buf[:len(s.buf)+len(b)]
|
||||
copy(s.buf[bufLen:], b)
|
||||
}
|
||||
|
||||
// resetBuf points buf at storage, sets the length to 0 and sets cap to be a
|
||||
// multiple of the rate.
|
||||
func (s *asmState) resetBuf() {
|
||||
max := (cap(s.storage) / s.rate) * s.rate
|
||||
s.buf = s.storage[:0:max]
|
||||
}
|
||||
|
||||
// Write (via the embedded io.Writer interface) adds more data to the running hash.
|
||||
// It never returns an error.
|
||||
func (s *asmState) Write(b []byte) (int, error) {
|
||||
if s.state != spongeAbsorbing {
|
||||
panic("sha3: write to sponge after read")
|
||||
}
|
||||
length := len(b)
|
||||
for len(b) > 0 {
|
||||
if len(s.buf) == 0 && len(b) >= cap(s.buf) {
|
||||
// Hash the data directly and push any remaining bytes
|
||||
// into the buffer.
|
||||
remainder := len(b) % s.rate
|
||||
kimd(s.function, &s.a, b[:len(b)-remainder])
|
||||
if remainder != 0 {
|
||||
s.copyIntoBuf(b[len(b)-remainder:])
|
||||
}
|
||||
return length, nil
|
||||
}
|
||||
|
||||
if len(s.buf) == cap(s.buf) {
|
||||
// flush the buffer
|
||||
kimd(s.function, &s.a, s.buf)
|
||||
s.buf = s.buf[:0]
|
||||
}
|
||||
|
||||
// copy as much as we can into the buffer
|
||||
n := len(b)
|
||||
if len(b) > cap(s.buf)-len(s.buf) {
|
||||
n = cap(s.buf) - len(s.buf)
|
||||
}
|
||||
s.copyIntoBuf(b[:n])
|
||||
b = b[n:]
|
||||
}
|
||||
return length, nil
|
||||
}
|
||||
|
||||
// Read squeezes an arbitrary number of bytes from the sponge.
|
||||
func (s *asmState) Read(out []byte) (n int, err error) {
|
||||
n = len(out)
|
||||
|
||||
// need to pad if we were absorbing
|
||||
if s.state == spongeAbsorbing {
|
||||
s.state = spongeSqueezing
|
||||
|
||||
// write hash directly into out if possible
|
||||
if len(out)%s.rate == 0 {
|
||||
klmd(s.function, &s.a, out, s.buf) // len(out) may be 0
|
||||
s.buf = s.buf[:0]
|
||||
return
|
||||
}
|
||||
|
||||
// write hash into buffer
|
||||
max := cap(s.buf)
|
||||
if max > len(out) {
|
||||
max = (len(out)/s.rate)*s.rate + s.rate
|
||||
}
|
||||
klmd(s.function, &s.a, s.buf[:max], s.buf)
|
||||
s.buf = s.buf[:max]
|
||||
}
|
||||
|
||||
for len(out) > 0 {
|
||||
// flush the buffer
|
||||
if len(s.buf) != 0 {
|
||||
c := copy(out, s.buf)
|
||||
out = out[c:]
|
||||
s.buf = s.buf[c:]
|
||||
continue
|
||||
}
|
||||
|
||||
// write hash directly into out if possible
|
||||
if len(out)%s.rate == 0 {
|
||||
klmd(s.function|nopad, &s.a, out, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// write hash into buffer
|
||||
s.resetBuf()
|
||||
if cap(s.buf) > len(out) {
|
||||
s.buf = s.buf[:(len(out)/s.rate)*s.rate+s.rate]
|
||||
}
|
||||
klmd(s.function|nopad, &s.a, s.buf, nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Sum appends the current hash to b and returns the resulting slice.
|
||||
// It does not change the underlying hash state.
|
||||
func (s *asmState) Sum(b []byte) []byte {
|
||||
if s.outputLen == 0 {
|
||||
panic("sha3: cannot call Sum on SHAKE functions")
|
||||
}
|
||||
|
||||
// Copy the state to preserve the original.
|
||||
a := s.a
|
||||
|
||||
// Hash the buffer. Note that we don't clear it because we
|
||||
// aren't updating the state.
|
||||
klmd(s.function, &a, nil, s.buf)
|
||||
return append(b, a[:s.outputLen]...)
|
||||
}
|
||||
|
||||
// Reset resets the Hash to its initial state.
|
||||
func (s *asmState) Reset() {
|
||||
for i := range s.a {
|
||||
s.a[i] = 0
|
||||
}
|
||||
s.resetBuf()
|
||||
s.state = spongeAbsorbing
|
||||
}
|
||||
|
||||
// Size returns the number of bytes Sum will return.
|
||||
func (s *asmState) Size() int {
|
||||
return s.outputLen
|
||||
}
|
||||
|
||||
// BlockSize returns the hash's underlying block size.
|
||||
// The Write method must be able to accept any amount
|
||||
// of data, but it may operate more efficiently if all writes
|
||||
// are a multiple of the block size.
|
||||
func (s *asmState) BlockSize() int {
|
||||
return s.rate
|
||||
}
|
||||
|
||||
// Clone returns a copy of the ShakeHash in its current state.
|
||||
func (s *asmState) Clone() ShakeHash {
|
||||
return s.clone()
|
||||
}
|
||||
|
||||
// new224Asm returns an assembly implementation of SHA3-224 if available,
|
||||
// otherwise it returns nil.
|
||||
func new224Asm() hash.Hash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(sha3_224)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// new256Asm returns an assembly implementation of SHA3-256 if available,
|
||||
// otherwise it returns nil.
|
||||
func new256Asm() hash.Hash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(sha3_256)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// new384Asm returns an assembly implementation of SHA3-384 if available,
|
||||
// otherwise it returns nil.
|
||||
func new384Asm() hash.Hash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(sha3_384)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// new512Asm returns an assembly implementation of SHA3-512 if available,
|
||||
// otherwise it returns nil.
|
||||
func new512Asm() hash.Hash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(sha3_512)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// newShake128Asm returns an assembly implementation of SHAKE-128 if available,
|
||||
// otherwise it returns nil.
|
||||
func newShake128Asm() ShakeHash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(shake_128)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// newShake256Asm returns an assembly implementation of SHAKE-256 if available,
|
||||
// otherwise it returns nil.
|
||||
func newShake256Asm() ShakeHash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(shake_256)
|
||||
}
|
||||
return nil
|
||||
}
|
34
vendor/golang.org/x/crypto/sha3/sha3_s390x.s
generated
vendored
Normal file
34
vendor/golang.org/x/crypto/sha3/sha3_s390x.s
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func kimd(function code, chain *[200]byte, src []byte)
|
||||
TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40
|
||||
MOVD function+0(FP), R0
|
||||
MOVD chain+8(FP), R1
|
||||
LMG src+16(FP), R2, R3 // R2=base, R3=len
|
||||
|
||||
continue:
|
||||
WORD $0xB93E0002 // KIMD --, R2
|
||||
BVS continue // continue if interrupted
|
||||
MOVD $0, R0 // reset R0 for pre-go1.8 compilers
|
||||
RET
|
||||
|
||||
// func klmd(function code, chain *[200]byte, dst, src []byte)
|
||||
TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64
|
||||
// TODO: SHAKE support
|
||||
MOVD function+0(FP), R0
|
||||
MOVD chain+8(FP), R1
|
||||
LMG dst+16(FP), R2, R3 // R2=base, R3=len
|
||||
LMG src+40(FP), R4, R5 // R4=base, R5=len
|
||||
|
||||
continue:
|
||||
WORD $0xB93F0024 // KLMD R2, R4
|
||||
BVS continue // continue if interrupted
|
||||
MOVD $0, R0 // reset R0 for pre-go1.8 compilers
|
||||
RET
|
173
vendor/golang.org/x/crypto/sha3/shake.go
generated
vendored
Normal file
173
vendor/golang.org/x/crypto/sha3/shake.go
generated
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
// Copyright 2014 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 sha3
|
||||
|
||||
// This file defines the ShakeHash interface, and provides
|
||||
// functions for creating SHAKE and cSHAKE instances, as well as utility
|
||||
// functions for hashing bytes to arbitrary-length output.
|
||||
//
|
||||
//
|
||||
// SHAKE implementation is based on FIPS PUB 202 [1]
|
||||
// cSHAKE implementations is based on NIST SP 800-185 [2]
|
||||
//
|
||||
// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
|
||||
// [2] https://doi.org/10.6028/NIST.SP.800-185
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
// ShakeHash defines the interface to hash functions that
|
||||
// support arbitrary-length output.
|
||||
type ShakeHash interface {
|
||||
// Write absorbs more data into the hash's state. It panics if input is
|
||||
// written to it after output has been read from it.
|
||||
io.Writer
|
||||
|
||||
// Read reads more output from the hash; reading affects the hash's
|
||||
// state. (ShakeHash.Read is thus very different from Hash.Sum)
|
||||
// It never returns an error.
|
||||
io.Reader
|
||||
|
||||
// Clone returns a copy of the ShakeHash in its current state.
|
||||
Clone() ShakeHash
|
||||
|
||||
// Reset resets the ShakeHash to its initial state.
|
||||
Reset()
|
||||
}
|
||||
|
||||
// cSHAKE specific context
|
||||
type cshakeState struct {
|
||||
*state // SHA-3 state context and Read/Write operations
|
||||
|
||||
// initBlock is the cSHAKE specific initialization set of bytes. It is initialized
|
||||
// by newCShake function and stores concatenation of N followed by S, encoded
|
||||
// by the method specified in 3.3 of [1].
|
||||
// It is stored here in order for Reset() to be able to put context into
|
||||
// initial state.
|
||||
initBlock []byte
|
||||
}
|
||||
|
||||
// Consts for configuring initial SHA-3 state
|
||||
const (
|
||||
dsbyteShake = 0x1f
|
||||
dsbyteCShake = 0x04
|
||||
rate128 = 168
|
||||
rate256 = 136
|
||||
)
|
||||
|
||||
func bytepad(input []byte, w int) []byte {
|
||||
// leftEncode always returns max 9 bytes
|
||||
buf := make([]byte, 0, 9+len(input)+w)
|
||||
buf = append(buf, leftEncode(uint64(w))...)
|
||||
buf = append(buf, input...)
|
||||
padlen := w - (len(buf) % w)
|
||||
return append(buf, make([]byte, padlen)...)
|
||||
}
|
||||
|
||||
func leftEncode(value uint64) []byte {
|
||||
var b [9]byte
|
||||
binary.BigEndian.PutUint64(b[1:], value)
|
||||
// Trim all but last leading zero bytes
|
||||
i := byte(1)
|
||||
for i < 8 && b[i] == 0 {
|
||||
i++
|
||||
}
|
||||
// Prepend number of encoded bytes
|
||||
b[i-1] = 9 - i
|
||||
return b[i-1:]
|
||||
}
|
||||
|
||||
func newCShake(N, S []byte, rate int, dsbyte byte) ShakeHash {
|
||||
c := cshakeState{state: &state{rate: rate, dsbyte: dsbyte}}
|
||||
|
||||
// leftEncode returns max 9 bytes
|
||||
c.initBlock = make([]byte, 0, 9*2+len(N)+len(S))
|
||||
c.initBlock = append(c.initBlock, leftEncode(uint64(len(N)*8))...)
|
||||
c.initBlock = append(c.initBlock, N...)
|
||||
c.initBlock = append(c.initBlock, leftEncode(uint64(len(S)*8))...)
|
||||
c.initBlock = append(c.initBlock, S...)
|
||||
c.Write(bytepad(c.initBlock, c.rate))
|
||||
return &c
|
||||
}
|
||||
|
||||
// Reset resets the hash to initial state.
|
||||
func (c *cshakeState) Reset() {
|
||||
c.state.Reset()
|
||||
c.Write(bytepad(c.initBlock, c.rate))
|
||||
}
|
||||
|
||||
// Clone returns copy of a cSHAKE context within its current state.
|
||||
func (c *cshakeState) Clone() ShakeHash {
|
||||
b := make([]byte, len(c.initBlock))
|
||||
copy(b, c.initBlock)
|
||||
return &cshakeState{state: c.clone(), initBlock: b}
|
||||
}
|
||||
|
||||
// Clone returns copy of SHAKE context within its current state.
|
||||
func (c *state) Clone() ShakeHash {
|
||||
return c.clone()
|
||||
}
|
||||
|
||||
// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
|
||||
// Its generic security strength is 128 bits against all attacks if at
|
||||
// least 32 bytes of its output are used.
|
||||
func NewShake128() ShakeHash {
|
||||
if h := newShake128Asm(); h != nil {
|
||||
return h
|
||||
}
|
||||
return &state{rate: rate128, dsbyte: dsbyteShake}
|
||||
}
|
||||
|
||||
// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
|
||||
// Its generic security strength is 256 bits against all attacks if
|
||||
// at least 64 bytes of its output are used.
|
||||
func NewShake256() ShakeHash {
|
||||
if h := newShake256Asm(); h != nil {
|
||||
return h
|
||||
}
|
||||
return &state{rate: rate256, dsbyte: dsbyteShake}
|
||||
}
|
||||
|
||||
// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
|
||||
// a customizable variant of SHAKE128.
|
||||
// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
|
||||
// desired. S is a customization byte string used for domain separation - two cSHAKE
|
||||
// computations on same input with different S yield unrelated outputs.
|
||||
// When N and S are both empty, this is equivalent to NewShake128.
|
||||
func NewCShake128(N, S []byte) ShakeHash {
|
||||
if len(N) == 0 && len(S) == 0 {
|
||||
return NewShake128()
|
||||
}
|
||||
return newCShake(N, S, rate128, dsbyteCShake)
|
||||
}
|
||||
|
||||
// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
|
||||
// a customizable variant of SHAKE256.
|
||||
// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
|
||||
// desired. S is a customization byte string used for domain separation - two cSHAKE
|
||||
// computations on same input with different S yield unrelated outputs.
|
||||
// When N and S are both empty, this is equivalent to NewShake256.
|
||||
func NewCShake256(N, S []byte) ShakeHash {
|
||||
if len(N) == 0 && len(S) == 0 {
|
||||
return NewShake256()
|
||||
}
|
||||
return newCShake(N, S, rate256, dsbyteCShake)
|
||||
}
|
||||
|
||||
// ShakeSum128 writes an arbitrary-length digest of data into hash.
|
||||
func ShakeSum128(hash, data []byte) {
|
||||
h := NewShake128()
|
||||
h.Write(data)
|
||||
h.Read(hash)
|
||||
}
|
||||
|
||||
// ShakeSum256 writes an arbitrary-length digest of data into hash.
|
||||
func ShakeSum256(hash, data []byte) {
|
||||
h := NewShake256()
|
||||
h.Write(data)
|
||||
h.Read(hash)
|
||||
}
|
20
vendor/golang.org/x/crypto/sha3/shake_generic.go
generated
vendored
Normal file
20
vendor/golang.org/x/crypto/sha3/shake_generic.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
//go:build !gc || purego || !s390x
|
||||
// +build !gc purego !s390x
|
||||
|
||||
package sha3
|
||||
|
||||
// newShake128Asm returns an assembly implementation of SHAKE-128 if available,
|
||||
// otherwise it returns nil.
|
||||
func newShake128Asm() ShakeHash {
|
||||
return nil
|
||||
}
|
||||
|
||||
// newShake256Asm returns an assembly implementation of SHAKE-256 if available,
|
||||
// otherwise it returns nil.
|
||||
func newShake256Asm() ShakeHash {
|
||||
return nil
|
||||
}
|
24
vendor/golang.org/x/crypto/sha3/xor.go
generated
vendored
Normal file
24
vendor/golang.org/x/crypto/sha3/xor.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
//go:build (!amd64 && !386 && !ppc64le) || purego
|
||||
// +build !amd64,!386,!ppc64le purego
|
||||
|
||||
package sha3
|
||||
|
||||
// A storageBuf is an aligned array of maxRate bytes.
|
||||
type storageBuf [maxRate]byte
|
||||
|
||||
func (b *storageBuf) asBytes() *[maxRate]byte {
|
||||
return (*[maxRate]byte)(b)
|
||||
}
|
||||
|
||||
var (
|
||||
xorIn = xorInGeneric
|
||||
copyOut = copyOutGeneric
|
||||
xorInUnaligned = xorInGeneric
|
||||
copyOutUnaligned = copyOutGeneric
|
||||
)
|
||||
|
||||
const xorImplementationUnaligned = "generic"
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user