Compare commits
6 commits
d4956100bf
...
2c997e3866
Author | SHA1 | Date | |
---|---|---|---|
2c997e3866 | |||
90825fa01b | |||
0358eeac53 | |||
414654585b | |||
a65c6bc394 | |||
46df74226f |
14 changed files with 446 additions and 299 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,3 +3,5 @@ blas
|
|||
!cmd/blas/
|
||||
Session.vim
|
||||
coverage.txt
|
||||
*.dlv
|
||||
*.core
|
||||
|
|
5
Makefile
5
Makefile
|
@ -4,11 +4,16 @@ all: build
|
|||
build:
|
||||
go build -o blas ./cmd/blas/
|
||||
|
||||
serve:
|
||||
go run ./cmd/blas/ serve ${BLAS_ARGS}
|
||||
|
||||
# pkg/frontend/frontend/hass_frontend:
|
||||
frontend:
|
||||
${FE}/script/setup
|
||||
${FE}/script/build_frontend
|
||||
|
||||
todo:
|
||||
rg -g '!Makefile' -g '!pkg/frontend/frontend/**' -A3 -C3 'XXX:|TODO:' .
|
||||
|
||||
debug:
|
||||
dlv debug ./cmd/blas/ ${ARGS}
|
||||
|
|
14
go.mod
14
go.mod
|
@ -3,9 +3,6 @@ module dynatron.me/x/blasphem
|
|||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/go-oauth2/oauth2 v3.9.2+incompatible
|
||||
github.com/go-oauth2/oauth2/v4 v4.5.1
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/jinzhu/copier v0.3.5
|
||||
|
@ -20,23 +17,16 @@ require (
|
|||
require (
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/labstack/gommon v0.3.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/tidwall/btree v1.4.4 // indirect
|
||||
github.com/tidwall/buntdb v1.2.10 // indirect
|
||||
github.com/tidwall/gjson v1.14.3 // indirect
|
||||
github.com/tidwall/grect v0.1.4 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/rtred v0.1.2 // indirect
|
||||
github.com/tidwall/tinyqueue v0.1.1 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||
golang.org/x/net v0.1.0 // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
|
||||
gopkg.in/oauth2.v3 v3.12.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
)
|
||||
|
|
161
go.sum
161
go.sum
|
@ -1,68 +1,20 @@
|
|||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
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/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8=
|
||||
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
|
||||
github.com/go-oauth2/oauth2 v3.9.2+incompatible h1:A8gSjq4110EgZDVk4ZtcpusynU2Fto9eM6sXvxL+EOs=
|
||||
github.com/go-oauth2/oauth2 v3.9.2+incompatible/go.mod h1:GGcZ+i513KxN4yS7zBYfmwo3P+cyGvCS675uCNmWv/g=
|
||||
github.com/go-oauth2/oauth2/v4 v4.5.1 h1:3vxp+cjLqDe1TbogbwtMyeHRHr1tD+ksrK7xNppYRDs=
|
||||
github.com/go-oauth2/oauth2/v4 v4.5.1/go.mod h1:wk/2uLImWIa9VVQDgxz99H2GDbhmfi/9/Xr+GvkSUSQ=
|
||||
github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
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/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
|
||||
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
|
||||
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
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/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
|
||||
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U=
|
||||
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
|
@ -75,8 +27,6 @@ github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL
|
|||
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
|
||||
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
|
@ -86,16 +36,6 @@ github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y
|
|||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs=
|
||||
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
|
@ -105,122 +45,43 @@ github.com/rs/zerolog v1.26.0/go.mod h1:yBiM87lvSqX8h0Ww4sdzNSkVYZ8dL2xjZJG1lAuG
|
|||
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
|
||||
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
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/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
|
||||
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tidwall/assert v0.1.0 h1:aWcKyRBUAdLoVebxo95N7+YZVTFF/ASTr7BN4sLP6XI=
|
||||
github.com/tidwall/btree v0.0.0-20170113224114-9876f1454cf0/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8=
|
||||
github.com/tidwall/btree v0.0.0-20191029221954-400434d76274/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8=
|
||||
github.com/tidwall/btree v1.4.4 h1:tOsRz2Upq6BEJz8T++C6THzNh9xGWymBOOSfA7ffNXY=
|
||||
github.com/tidwall/btree v1.4.4/go.mod h1:LGm8L/DZjPLmeWGjv5kFrY8dL4uVhMmzmmLYmsObdKE=
|
||||
github.com/tidwall/buntdb v1.1.0/go.mod h1:Y39xhcDW10WlyYXeLgGftXVbjtM0QP+/kpz8xl9cbzE=
|
||||
github.com/tidwall/buntdb v1.1.2/go.mod h1:xAzi36Hir4FarpSHyfuZ6JzPJdjRZ8QlLZSntE2mqlI=
|
||||
github.com/tidwall/buntdb v1.2.10 h1:U/ebfkmYPBnyiNZIirUiWFcxA/mgzjbKlyPynFsPtyM=
|
||||
github.com/tidwall/buntdb v1.2.10/go.mod h1:lZZrZUWzlyDJKlLQ6DKAy53LnG7m5kHyrEHvvcDmBpU=
|
||||
github.com/tidwall/gjson v1.3.2/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
|
||||
github.com/tidwall/gjson v1.3.4/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
|
||||
github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
|
||||
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb/go.mod h1:lKYYLFIr9OIgdgrtgkZ9zgRxRdvPYsExnYBsEAd8W5M=
|
||||
github.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg=
|
||||
github.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q=
|
||||
github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8=
|
||||
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/rtred v0.1.2 h1:exmoQtOLvDoO8ud++6LwVsAMTu0KPzLTUrMln8u1yu8=
|
||||
github.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSRxCHFQ=
|
||||
github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e/go.mod h1:/h+UnNGt0IhNNJLkGikcdcJqm66zGD/uJGMRxK/9+Ao=
|
||||
github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563/go.mod h1:mLqSmt7Dv/CNneF2wfcChfN1rvapyQr01LGKnKex0DQ=
|
||||
github.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE=
|
||||
github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
|
||||
github.com/valyala/fasthttp v1.34.0 h1:d3AAQJ2DRcxJYHm7OXNXtXt2as1vMDfxeIcFvhmGGm4=
|
||||
github.com/valyala/fasthttp v1.34.0/go.mod h1:epZA5N+7pY6ZaEKRmstzOuYJx9HI8DI1oaCGZpdH4h0=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
|
||||
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
|
||||
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
|
||||
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
|
||||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
|
||||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
|
||||
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/ziflex/lecho/v3 v3.1.0 h1:65bSzSc0yw7EEhi44lMnkOI877ZzbE7tGDWfYCQXZwI=
|
||||
github.com/ziflex/lecho/v3 v3.1.0/go.mod h1:dwQ6xCAKmSBHhwZ6XmiAiDptD7iklVkW7xQYGUncX0Q=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/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/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/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-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
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/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/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=
|
||||
|
@ -229,14 +90,10 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/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/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
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/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
|
@ -245,35 +102,17 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE=
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/oauth2.v3 v3.12.0 h1:yOffAPoolH/i2JxwmC+pgtnY3362iPahsDpLXfDFvNg=
|
||||
gopkg.in/oauth2.v3 v3.12.0/go.mod h1:XEYgKqWX095YiPT+Aw5y3tCn+7/FMnlTFKrupgSiJ3I=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/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-20200615113413-eeeca48fe776/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=
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/go-oauth2/oauth2/models"
|
||||
"github.com/go-oauth2/oauth2/server"
|
||||
"github.com/go-oauth2/oauth2/v4/generates"
|
||||
"github.com/go-oauth2/oauth2/v4/manage"
|
||||
"github.com/go-oauth2/oauth2/v4/store"
|
||||
"github.com/google/uuid"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"dynatron.me/x/blasphem/pkg/auth/provider"
|
||||
"dynatron.me/x/blasphem/pkg/frontend"
|
||||
"dynatron.me/x/blasphem/pkg/storage"
|
||||
|
||||
// providers
|
||||
_ "dynatron.me/x/blasphem/pkg/auth/provider/hass"
|
||||
_ "dynatron.me/x/blasphem/pkg/auth/provider/trustednets"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -26,15 +25,20 @@ var (
|
|||
)
|
||||
|
||||
type Authenticator struct {
|
||||
manager *manage.Manager
|
||||
store AuthStore
|
||||
flows FlowStore
|
||||
sessions SessionStore
|
||||
providers map[string]AuthProvider
|
||||
providers map[string]provider.AuthProvider
|
||||
}
|
||||
|
||||
type AuthError struct {
|
||||
Error string `json:"error"`
|
||||
Description string `json:"error_description"`
|
||||
}
|
||||
|
||||
func (a *Authenticator) InstallRoutes(e *echo.Echo) {
|
||||
authG := e.Group("/auth")
|
||||
authG.GET("/authorize", a.AuthorizeHandler)
|
||||
authG.GET("/authorize", frontend.AliasHandler("authorize.html"))
|
||||
authG.GET("/providers", a.ProvidersHandler)
|
||||
authG.POST("/token", a.TokenHandler)
|
||||
|
||||
|
@ -43,46 +47,33 @@ func (a *Authenticator) InstallRoutes(e *echo.Echo) {
|
|||
loginFlow := authG.Group("/login_flow") // TODO: add IP address affinity middleware
|
||||
loginFlow.POST("/:flow_id", a.LoginFlowHandler)
|
||||
loginFlow.DELETE("/:flow_id", a.LoginFlowDeleteHandler)
|
||||
|
||||
}
|
||||
|
||||
func (a *Authenticator) InitAuth(s storage.Store) error {
|
||||
a.manager = manage.NewDefaultManager()
|
||||
a.providers = make(map[string]provider.AuthProvider)
|
||||
for _, pI := range provider.Providers {
|
||||
nProv, err := pI(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.manager.SetAuthorizeCodeTokenCfg(manage.DefaultAuthorizeCodeTokenCfg)
|
||||
|
||||
// token store
|
||||
a.manager.MustTokenStorage(store.NewMemoryTokenStore())
|
||||
|
||||
// generate jwt access token
|
||||
a.manager.MapAccessGenerate(generates.NewJWTAccessGenerate("", []byte("00000000"), jwt.SigningMethodHS512))
|
||||
|
||||
clientStore := store.NewClientStore()
|
||||
clientStore.Set(idvar, &models.Client{
|
||||
ID: idvar,
|
||||
Secret: secretvar,
|
||||
Domain: domainvar,
|
||||
})
|
||||
manager.MapClientStorage(clientStore)
|
||||
|
||||
srv := server.NewServer(server.NewConfig(), manager)
|
||||
|
||||
a.flows = make(FlowStore)
|
||||
a.sessions.init()
|
||||
hap, err := NewHAProvider(s)
|
||||
if err != nil {
|
||||
return err
|
||||
a.providers[nProv.ProviderType()] = nProv
|
||||
}
|
||||
|
||||
// XXX: yuck
|
||||
a.providers = map[string]AuthProvider{
|
||||
hap.ProviderType(): hap,
|
||||
a.flows = make(FlowStore)
|
||||
|
||||
a.sessions.init()
|
||||
|
||||
var err error
|
||||
a.store, err = a.newAuthStore(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Authenticator) Provider(name string) AuthProvider {
|
||||
func (a *Authenticator) Provider(name string) provider.AuthProvider {
|
||||
p, ok := a.providers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
|
@ -91,77 +82,43 @@ func (a *Authenticator) Provider(name string) AuthProvider {
|
|||
return p
|
||||
}
|
||||
|
||||
type AuthProvider interface { // TODO: this should include stepping
|
||||
ProviderName() string
|
||||
ProviderID() *string
|
||||
ProviderType() string
|
||||
ProviderBase() AuthProviderBase
|
||||
FlowSchema() []FlowSchemaItem
|
||||
ValidateCreds(reqMap map[string]interface{}) bool
|
||||
}
|
||||
|
||||
type AuthProviderBase struct {
|
||||
Name string `json:"name"`
|
||||
ID *string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
func (bp *AuthProviderBase) ProviderName() string { return bp.Name }
|
||||
func (bp *AuthProviderBase) ProviderID() *string { return bp.ID }
|
||||
func (bp *AuthProviderBase) ProviderType() string { return bp.Type }
|
||||
func (bp *AuthProviderBase) ProviderBase() AuthProviderBase { return *bp }
|
||||
|
||||
var HomeAssistant = "homeassistant"
|
||||
|
||||
// TODO: make this configurable
|
||||
func (a *Authenticator) ProvidersHandler(c echo.Context) error {
|
||||
providers := []AuthProviderBase{
|
||||
providers := []provider.AuthProviderBase{
|
||||
a.Provider(HomeAssistant).ProviderBase(),
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusOK, providers)
|
||||
}
|
||||
|
||||
func (s *Authenticator) AuthorizeHandler(c echo.Context) error {
|
||||
authContents, err := frontend.RootFS.Open("authorize.html")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer authContents.Close()
|
||||
|
||||
b, err := io.ReadAll(authContents)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.HTML(http.StatusOK, string(b))
|
||||
}
|
||||
|
||||
func (a *Authenticator) Check(f *Flow, rm map[string]interface{}) error {
|
||||
func (a *Authenticator) Check(f *Flow, rm map[string]interface{}) (provider.ProviderUser, error) {
|
||||
cID, hasCID := rm["client_id"]
|
||||
if !hasCID || cID != f.request.ClientID {
|
||||
return ErrInvalidAuth
|
||||
cIDStr, cidIsStr := cID.(string)
|
||||
if !hasCID || !cidIsStr || cIDStr == "" || cIDStr != string(f.request.ClientID) {
|
||||
return nil, ErrInvalidAuth
|
||||
}
|
||||
|
||||
for _, h := range f.Handler {
|
||||
if h == nil {
|
||||
return ErrInvalidHandler
|
||||
return nil, ErrInvalidHandler
|
||||
}
|
||||
|
||||
p := a.Provider(*h)
|
||||
if p == nil {
|
||||
return ErrInvalidAuth
|
||||
return nil, ErrInvalidAuth
|
||||
}
|
||||
|
||||
success := p.ValidateCreds(rm)
|
||||
user, success := p.ValidateCreds(rm)
|
||||
|
||||
if success {
|
||||
log.Info().Str("user", rm["username"].(string)).Msg("Login success")
|
||||
return nil
|
||||
log.Info().Interface("user", user.ProviderUserData()).Msg("Login success")
|
||||
return user, nil
|
||||
}
|
||||
}
|
||||
|
||||
return ErrInvalidAuth
|
||||
return nil, ErrInvalidAuth
|
||||
}
|
||||
|
||||
func genUUID() string {
|
||||
|
@ -170,3 +127,12 @@ func genUUID() string {
|
|||
|
||||
return hex.EncodeToString(u[:])
|
||||
}
|
||||
|
||||
func genHex(l int) string {
|
||||
b := make([]byte, l)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
|
|
|
@ -9,22 +9,17 @@ import (
|
|||
"github.com/labstack/echo/v4"
|
||||
|
||||
"dynatron.me/x/blasphem/internal/common"
|
||||
"dynatron.me/x/blasphem/pkg/auth/provider"
|
||||
)
|
||||
|
||||
type FlowStore map[FlowID]*Flow
|
||||
|
||||
type FlowRequest struct {
|
||||
ClientID string `json:"client_id"`
|
||||
ClientID ClientID `json:"client_id"`
|
||||
Handler []*string `json:"handler"`
|
||||
RedirectURI string `json:"redirect_uri"`
|
||||
}
|
||||
|
||||
type FlowSchemaItem struct {
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
}
|
||||
|
||||
type FlowType string
|
||||
|
||||
const (
|
||||
|
@ -44,7 +39,7 @@ type Flow struct {
|
|||
ID FlowID `json:"flow_id"`
|
||||
Handler []*string `json:"handler"`
|
||||
StepID *Step `json:"step_id,omitempty"`
|
||||
Schema []FlowSchemaItem `json:"data_schema"`
|
||||
Schema []provider.FlowSchemaItem `json:"data_schema"`
|
||||
Errors interface{} `json:"errors"`
|
||||
DescPlace *string `json:"description_placeholders"`
|
||||
LastStep *string `json:"last_step"`
|
||||
|
@ -86,7 +81,7 @@ func (fs FlowStore) Get(id FlowID) *Flow {
|
|||
}
|
||||
|
||||
func (a *Authenticator) NewFlow(r *FlowRequest) *Flow {
|
||||
var sch []FlowSchemaItem
|
||||
var sch []provider.FlowSchemaItem
|
||||
|
||||
for _, h := range r.Handler {
|
||||
if h == nil {
|
||||
|
@ -147,7 +142,7 @@ func (f *Flow) progress(a *Authenticator, c echo.Context) error {
|
|||
}
|
||||
}
|
||||
}
|
||||
err = a.Check(f, rm)
|
||||
user, err := a.Check(f, rm)
|
||||
switch err {
|
||||
case nil:
|
||||
var finishedFlow struct {
|
||||
|
@ -158,13 +153,13 @@ func (f *Flow) progress(a *Authenticator, c echo.Context) error {
|
|||
Type FlowType `json:"type"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
// TODO: setup the session. delete the flow.
|
||||
|
||||
a.flows.Remove(f)
|
||||
copier.Copy(&finishedFlow, f)
|
||||
finishedFlow.Type = TypeCreateEntry
|
||||
finishedFlow.Title = common.AppName
|
||||
finishedFlow.Version = 1
|
||||
finishedFlow.Result = a.NewToken(c.Request(), f)
|
||||
finishedFlow.Result = a.NewToken(c.Request(), user, f)
|
||||
|
||||
f.redirect(c)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package auth
|
||||
package hass
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/rs/zerolog/log"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"dynatron.me/x/blasphem/pkg/auth/provider"
|
||||
"dynatron.me/x/blasphem/pkg/storage"
|
||||
)
|
||||
|
||||
|
@ -13,19 +14,35 @@ const (
|
|||
HAProviderKey = "auth_provider.homeassistant"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
type HAUser struct {
|
||||
Password string `json:"password"`
|
||||
Username string `json:"username"`
|
||||
|
||||
provider.AuthProvider `json:"-"`
|
||||
}
|
||||
|
||||
func (hau *HAUser) UserData() interface{} {
|
||||
return UserData{
|
||||
Username: hau.Username,
|
||||
}
|
||||
}
|
||||
|
||||
type UserData struct {
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
const HomeAssistant = "homeassistant"
|
||||
|
||||
func (h *HAUser) ProviderUserData() interface{} { return h.UserData() }
|
||||
|
||||
type HomeAssistantProvider struct {
|
||||
AuthProviderBase `json:"-"`
|
||||
Users []User `json:"users"`
|
||||
provider.AuthProviderBase `json:"-"`
|
||||
Users []HAUser `json:"users"`
|
||||
}
|
||||
|
||||
func NewHAProvider(s storage.Store) (*HomeAssistantProvider, error) {
|
||||
func NewHAProvider(s storage.Store) (provider.AuthProvider, error) {
|
||||
hap := &HomeAssistantProvider{
|
||||
AuthProviderBase: AuthProviderBase{
|
||||
AuthProviderBase: provider.AuthProviderBase{
|
||||
Name: "Home Assistant Local",
|
||||
Type: HomeAssistant,
|
||||
},
|
||||
|
@ -36,6 +53,10 @@ func NewHAProvider(s storage.Store) (*HomeAssistantProvider, error) {
|
|||
return hap, err
|
||||
}
|
||||
|
||||
for i := range hap.Users {
|
||||
hap.Users[i].AuthProvider = hap
|
||||
}
|
||||
|
||||
return hap, nil
|
||||
}
|
||||
|
||||
|
@ -43,16 +64,16 @@ func (hap *HomeAssistantProvider) hashPass(p string) ([]byte, error) {
|
|||
return bcrypt.GenerateFromPassword([]byte(p), bcrypt.DefaultCost)
|
||||
}
|
||||
|
||||
func (hap *HomeAssistantProvider) ValidateCreds(rm map[string]interface{}) bool {
|
||||
func (hap *HomeAssistantProvider) ValidateCreds(rm map[string]interface{}) (provider.ProviderUser, bool) {
|
||||
usernameE, hasU := rm["username"]
|
||||
passwordE, hasP := rm["password"]
|
||||
username, unStr := usernameE.(string)
|
||||
password, paStr := passwordE.(string)
|
||||
if !hasU || !hasP || !unStr || !paStr || username == "" || password == "" {
|
||||
return false
|
||||
return nil, false
|
||||
}
|
||||
|
||||
var found *User
|
||||
var found *HAUser
|
||||
|
||||
const dummyHash = "$2b$12$CiuFGszHx9eNHxPuQcwBWez4CwDTOcLTX5CbOpV6gef2nYuXkY7BO"
|
||||
|
||||
|
@ -64,26 +85,30 @@ func (hap *HomeAssistantProvider) ValidateCreds(rm map[string]interface{}) bool
|
|||
|
||||
if found == nil { // one more compare to thwart timing attacks
|
||||
bcrypt.CompareHashAndPassword([]byte("foo"), []byte(dummyHash))
|
||||
return false
|
||||
return nil, false
|
||||
}
|
||||
|
||||
var hash []byte
|
||||
hash, err := base64.StdEncoding.DecodeString(found.Password)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("b64 encode fail")
|
||||
return false
|
||||
return nil, false
|
||||
}
|
||||
|
||||
err = bcrypt.CompareHashAndPassword(hash, []byte(password))
|
||||
if err == nil {
|
||||
return true
|
||||
return found, true
|
||||
}
|
||||
|
||||
return false
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (hap *HomeAssistantProvider) FlowSchema() []FlowSchemaItem {
|
||||
return []FlowSchemaItem{
|
||||
func (hap *HomeAssistantProvider) NewCredData() interface{} {
|
||||
return &UserData{}
|
||||
}
|
||||
|
||||
func (hap *HomeAssistantProvider) FlowSchema() []provider.FlowSchemaItem {
|
||||
return []provider.FlowSchemaItem{
|
||||
{
|
||||
Type: "string",
|
||||
Name: "username",
|
||||
|
@ -96,3 +121,8 @@ func (hap *HomeAssistantProvider) FlowSchema() []FlowSchemaItem {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
provider.Register(HomeAssistant, NewHAProvider)
|
||||
}
|
||||
|
51
pkg/auth/provider/provider.go
Normal file
51
pkg/auth/provider/provider.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"dynatron.me/x/blasphem/pkg/storage"
|
||||
)
|
||||
|
||||
type Constructor func(storage.Store) (AuthProvider, error)
|
||||
|
||||
var Providers = make(map[string]Constructor)
|
||||
|
||||
type AuthProvider interface { // TODO: this should include stepping
|
||||
AuthProviderMetadata
|
||||
ProviderBase() AuthProviderBase
|
||||
FlowSchema() []FlowSchemaItem
|
||||
NewCredData() interface{}
|
||||
ValidateCreds(reqMap map[string]interface{}) (user ProviderUser, success bool)
|
||||
}
|
||||
|
||||
func Register(providerName string, f func(storage.Store) (AuthProvider, error)) {
|
||||
Providers[providerName] = f
|
||||
}
|
||||
|
||||
type ProviderUser interface {
|
||||
AuthProviderMetadata
|
||||
ProviderUserData() interface{}
|
||||
}
|
||||
|
||||
type AuthProviderBase struct {
|
||||
Name string `json:"name"`
|
||||
ID *string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type AuthProviderMetadata interface {
|
||||
ProviderName() string
|
||||
ProviderID() *string
|
||||
ProviderType() string
|
||||
}
|
||||
|
||||
func (bp *AuthProviderBase) ProviderName() string { return bp.Name }
|
||||
func (bp *AuthProviderBase) ProviderID() *string { return bp.ID }
|
||||
func (bp *AuthProviderBase) ProviderType() string { return bp.Type }
|
||||
func (bp *AuthProviderBase) ProviderBase() AuthProviderBase { return *bp }
|
||||
|
||||
type FlowSchemaItem struct {
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
}
|
||||
|
||||
|
72
pkg/auth/provider/trustednets/trustednets.go
Normal file
72
pkg/auth/provider/trustednets/trustednets.go
Normal file
|
@ -0,0 +1,72 @@
|
|||
package trustednets
|
||||
|
||||
// TODO: This doesn't work at all
|
||||
|
||||
import (
|
||||
"dynatron.me/x/blasphem/pkg/auth/provider"
|
||||
"dynatron.me/x/blasphem/pkg/storage"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
UserID string `json:"user_id"`
|
||||
|
||||
provider.AuthProvider `json:"-"`
|
||||
}
|
||||
|
||||
func (hau *User) UserData() interface{} {
|
||||
return UserData{
|
||||
UserID: hau.UserID,
|
||||
}
|
||||
}
|
||||
|
||||
type UserData struct {
|
||||
UserID string `json:"user_id"`
|
||||
}
|
||||
|
||||
const TrustedNetworks = "trusted_networks"
|
||||
|
||||
func (h *User) ProviderUserData() interface{} { return h.UserData() }
|
||||
|
||||
type TrustedNetworksProvider struct {
|
||||
provider.AuthProviderBase `json:"-"`
|
||||
}
|
||||
|
||||
func New(s storage.Store) (provider.AuthProvider, error) {
|
||||
hap := &TrustedNetworksProvider{
|
||||
AuthProviderBase: provider.AuthProviderBase{
|
||||
Name: "Trusted Networks",
|
||||
Type: TrustedNetworks,
|
||||
},
|
||||
}
|
||||
|
||||
return hap, nil
|
||||
}
|
||||
|
||||
// TODO: To implement this, ValidateCreds needs to be changed to accept an http.Request, or the echo context.
|
||||
func (hap *TrustedNetworksProvider) ValidateCreds(rm map[string]interface{}) (provider.ProviderUser, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (hap *TrustedNetworksProvider) NewCredData() interface{} {
|
||||
return &UserData{}
|
||||
}
|
||||
|
||||
func (hap *TrustedNetworksProvider) FlowSchema() []provider.FlowSchemaItem {
|
||||
return []provider.FlowSchemaItem{
|
||||
{
|
||||
Type: "string",
|
||||
Name: "username",
|
||||
Required: true,
|
||||
},
|
||||
{
|
||||
Type: "string",
|
||||
Name: "password",
|
||||
Required: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
provider.Register(TrustedNetworks, New)
|
||||
}
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
|
||||
"dynatron.me/x/blasphem/pkg/auth/provider"
|
||||
)
|
||||
|
||||
type SessionStore struct {
|
||||
|
@ -14,11 +17,18 @@ type SessionStore struct {
|
|||
|
||||
type TokenID string
|
||||
|
||||
func (t *TokenID) IsValid() bool {
|
||||
// TODO: more validation than this
|
||||
return *t != ""
|
||||
}
|
||||
|
||||
type Token struct { // TODO: jwt bro
|
||||
ID TokenID
|
||||
Ctime time.Time
|
||||
Expires time.Time
|
||||
Addr string
|
||||
|
||||
user provider.ProviderUser `json:"-"`
|
||||
}
|
||||
|
||||
func (ss *SessionStore) init() {
|
||||
|
@ -42,20 +52,56 @@ func (ss *SessionStore) register(t *Token) {
|
|||
ss.s[t.ID] = t
|
||||
}
|
||||
|
||||
func (ss *SessionStore) verify(tr *TokenRequest, r *http.Request) bool {
|
||||
func (ss *SessionStore) verify(tr *TokenRequest, r *http.Request) (provider.ProviderUser, bool) {
|
||||
if t, hasToken := ss.s[tr.Code]; hasToken {
|
||||
// TODO: JWT
|
||||
if t.Expires.After(time.Now()) {
|
||||
return true
|
||||
return t.user, true
|
||||
} else {
|
||||
delete(ss.s, t.ID)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return nil, false
|
||||
}
|
||||
|
||||
type Credential struct {
|
||||
ID CredID `json:"id"`
|
||||
UserID UserID `json:"user_id"`
|
||||
AuthProviderType string `json:"auth_provider_type"`
|
||||
AuthProviderID *string `json:"auth_provider_id"`
|
||||
DataRaw json.RawMessage `json:"data,omitempty"`
|
||||
user provider.ProviderUser
|
||||
}
|
||||
|
||||
func (cred *Credential) MarshalJSON() ([]byte, error) {
|
||||
rm := map[string]interface{}{
|
||||
"id": cred.ID,
|
||||
"user_id": cred.UserID,
|
||||
"auth_provider_type": cred.user.ProviderType(),
|
||||
"auth_provider_id": cred.user.ProviderID(),
|
||||
}
|
||||
|
||||
providerData := cred.user.ProviderUserData()
|
||||
if providerData != nil {
|
||||
rm["data"] = providerData
|
||||
}
|
||||
|
||||
return json.Marshal(rm)
|
||||
}
|
||||
|
||||
func (ss *SessionStore) verifyAndGetCredential(tr *TokenRequest, r *http.Request) *Credential {
|
||||
user, success := ss.verify(tr, r)
|
||||
if !success {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &Credential{user: user}
|
||||
}
|
||||
|
||||
const defaultExpiration = 2 * time.Hour
|
||||
|
||||
func (a *Authenticator) NewToken(r *http.Request, f *Flow) TokenID {
|
||||
func (a *Authenticator) NewToken(r *http.Request, user provider.ProviderUser, f *Flow) TokenID {
|
||||
id := TokenID(genUUID())
|
||||
|
||||
t := &Token{
|
||||
|
@ -63,6 +109,8 @@ func (a *Authenticator) NewToken(r *http.Request, f *Flow) TokenID {
|
|||
Ctime: time.Now(),
|
||||
Expires: time.Now().Add(defaultExpiration),
|
||||
Addr: r.RemoteAddr,
|
||||
|
||||
user: user,
|
||||
}
|
||||
|
||||
a.sessions.register(t)
|
||||
|
@ -70,22 +118,57 @@ func (a *Authenticator) NewToken(r *http.Request, f *Flow) TokenID {
|
|||
return id
|
||||
}
|
||||
|
||||
type GrantType string
|
||||
|
||||
const (
|
||||
GTAuthorizationCode GrantType = "authorization_code"
|
||||
GTRefreshToken GrantType = "refresh_token"
|
||||
)
|
||||
|
||||
type ClientID string
|
||||
|
||||
func (c *ClientID) IsValid() bool {
|
||||
// TODO: || !indieauth.VerifyClientID(rq.ClientID)?
|
||||
return *c != ""
|
||||
}
|
||||
|
||||
type TokenRequest struct {
|
||||
ClientID string `query:"client_id"` // TODO: validate this?
|
||||
Code TokenID `query:"code"`
|
||||
GrantType string `query:"grant_type"`
|
||||
ClientID ClientID `form:"client_id"`
|
||||
Code TokenID `form:"code"`
|
||||
GrantType GrantType `form:"grant_type"`
|
||||
}
|
||||
|
||||
func (a *Authenticator) TokenHandler(c echo.Context) error {
|
||||
var rq TokenRequest
|
||||
err := c.Bind(&rq)
|
||||
rq := new(TokenRequest)
|
||||
err := c.Bind(rq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if a.sessions.verify(&rq, c.Request()) {
|
||||
// TODO: success
|
||||
return c.String(http.StatusOK, "token good I guess")
|
||||
switch rq.GrantType {
|
||||
case GTAuthorizationCode:
|
||||
if !rq.ClientID.IsValid() {
|
||||
return c.JSON(http.StatusBadRequest, AuthError{Error: "invalid_request", Description: "invalid client ID"})
|
||||
}
|
||||
|
||||
if !rq.Code.IsValid() {
|
||||
return c.JSON(http.StatusBadRequest, AuthError{Error: "invalid_request", Description: "invalid code"})
|
||||
}
|
||||
|
||||
if cred := a.sessions.verifyAndGetCredential(rq, c.Request()); cred != nil {
|
||||
// TODO: success
|
||||
user, err := a.getOrCreateUser(cred)
|
||||
if err != nil {
|
||||
return c.JSON(http.StatusUnauthorized, AuthError{Error: "access_denied", Description: "bad user"})
|
||||
}
|
||||
|
||||
if err := user.allowedToAuth(); err != nil {
|
||||
return c.JSON(http.StatusUnauthorized, AuthError{Error: "access_denied", Description: err.Error()})
|
||||
}
|
||||
return c.String(http.StatusOK, "token good I guess")
|
||||
}
|
||||
case GTRefreshToken:
|
||||
return c.String(http.StatusNotImplemented, "not implemented")
|
||||
}
|
||||
|
||||
return c.String(http.StatusUnauthorized, "token bad I guess")
|
||||
|
|
51
pkg/auth/store.go
Normal file
51
pkg/auth/store.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"encoding/json"
|
||||
|
||||
"dynatron.me/x/blasphem/pkg/storage"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthStoreKey = "auth"
|
||||
)
|
||||
|
||||
|
||||
type AuthStore interface {
|
||||
}
|
||||
|
||||
type authStore struct {
|
||||
Users []User `json:"users"`
|
||||
Groups interface {} `json:"groups"`
|
||||
Credentials []Credential `json:"credentials"`
|
||||
|
||||
userMap map[UserID]*User
|
||||
}
|
||||
|
||||
func (a *Authenticator) newAuthStore(s storage.Store) (as *authStore, err error) {
|
||||
as = &authStore{}
|
||||
err = s.Get(AuthStoreKey, as)
|
||||
|
||||
as.userMap = make(map[UserID]*User)
|
||||
|
||||
for _, u := range as.Users {
|
||||
as.userMap[u.ID] = &u
|
||||
}
|
||||
|
||||
for _, c := range as.Credentials {
|
||||
prov := a.Provider(c.AuthProviderType)
|
||||
if prov == nil {
|
||||
return nil, fmt.Errorf("no such provider %s", c.AuthProviderType)
|
||||
}
|
||||
|
||||
pd := prov.NewCredData()
|
||||
|
||||
err := json.Unmarshal(c.DataRaw, pd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
42
pkg/auth/user.go
Normal file
42
pkg/auth/user.go
Normal file
|
@ -0,0 +1,42 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type UserID string
|
||||
type GroupID string
|
||||
type CredID string
|
||||
|
||||
type User struct {
|
||||
ID UserID `json:"id"`
|
||||
GroupIDs []GroupID `json:"group_ids"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
UserMetadata
|
||||
}
|
||||
|
||||
type UserMetadata struct {
|
||||
Active bool `json:"is_active"`
|
||||
Owner bool `json:"is_owner"`
|
||||
LocalOnly bool `json:"local_only"`
|
||||
SystemGenerated bool `json:"system_generated"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (u *User) allowedToAuth() error {
|
||||
if !u.Active {
|
||||
return errors.New("user disabled")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Authenticator) getOrCreateUser(c *Credential) (*User, error) {
|
||||
log.Debug().Interface("userdata", c.user.ProviderUserData()).Msg("getOrCreateUser")
|
||||
panic("not implemented")
|
||||
return &User{}, nil
|
||||
}
|
||||
|
||||
|
|
@ -2,8 +2,11 @@ package frontend
|
|||
|
||||
import (
|
||||
"embed"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
//go:embed frontend/hass_frontend
|
||||
|
@ -11,14 +14,32 @@ var root embed.FS
|
|||
|
||||
var RootFS fs.FS
|
||||
|
||||
var FSHandler http.Handler
|
||||
var FSHandler echo.HandlerFunc
|
||||
|
||||
func AliasHandler(toFile string) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
file, err := RootFS.Open(toFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
b, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.HTML(http.StatusOK, string(b))
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
|
||||
RootFS, err = fs.Sub(root, "frontend/hass_frontend")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
FSHandler = http.FileServer(http.FS(RootFS))
|
||||
FSHandler = echo.StaticDirectoryHandler(RootFS, false)
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ type Server struct {
|
|||
}
|
||||
|
||||
func (s *Server) installRoutes() {
|
||||
s.GET("/", echo.WrapHandler(frontend.FSHandler))
|
||||
s.GET("/*", frontend.FSHandler)
|
||||
s.GET("/api/websocket", s.wsHandler)
|
||||
|
||||
s.Authenticator.InstallRoutes(s.Echo)
|
||||
|
|
Loading…
Reference in a new issue