diff --git a/go.mod b/go.mod index c4bc5b8..4466bb5 100644 --- a/go.mod +++ b/go.mod @@ -24,4 +24,5 @@ require ( golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect golang.org/x/text v0.3.4 // indirect gosrc.io/xmpp v0.5.1 + sour.is/x/toolbox v0.12.17 ) diff --git a/go.sum b/go.sum index 0b67024..857a972 100644 --- a/go.sum +++ b/go.sum @@ -1,14 +1,37 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/99designs/gqlgen v0.10.1/go.mod h1:IviubpnyI4gbBcj8IcxSSc/Q/+af5riwCmJmwF0uaPE= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/Masterminds/squirrel v0.0.0-20190511014652-b4b75d10d7bf/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/agnivade/wasmbrowsertest v0.3.1/go.mod h1:zQt6ZTdl338xxRaMW395qccVE2eQm0SjC/SDz0mPWQI= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bouk/monkey v1.0.0/go.mod h1:PG/63f4XEUlVyW1ttIeOJmJhhe1+t9EC/je3eTjvFhE= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cgilling/dbstats v0.0.0-20150427045024-c9db8cf218e6/go.mod h1:fsf3+k/VvGOE9sF2B9d6PBcZOzQIlDJhn2LhBqF/4VY= github.com/chromedp/cdproto v0.0.0-20190614062957-d6d2f92b486d/go.mod h1:S8mB5wY3vV+vRIzf39xDXsw3XKYewW9X6rW2aEmkrSw= github.com/chromedp/cdproto v0.0.0-20190621002710-8cbd498dd7a0/go.mod h1:S8mB5wY3vV+vRIzf39xDXsw3XKYewW9X6rW2aEmkrSw= github.com/chromedp/cdproto v0.0.0-20190812224334-39ef923dcb8d/go.mod h1:0YChpVzuLJC5CPr+x3xkHN6Z8KOSXjNbL7qV8Wc4GW0= github.com/chromedp/cdproto v0.0.0-20190926234355-1b4886c6fad6/go.mod h1:0YChpVzuLJC5CPr+x3xkHN6Z8KOSXjNbL7qV8Wc4GW0= github.com/chromedp/chromedp v0.3.1-0.20190619195644-fd957a4d2901/go.mod h1:mJdvfrVn594N9tfiPecUidF6W5jPRKHymqHfzbobPsM= github.com/chromedp/chromedp v0.4.0/go.mod h1:DC3QUn4mJ24dwjcaGQLoZrhm4X/uPHZ6spDbS2uFhm4= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 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/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= @@ -16,16 +39,32 @@ github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-interpreter/wagon v0.5.1-0.20190713202023-55a163980b6c/go.mod h1:5+b/MBYkclRZngKF5s6qrgWxSLgE9F5dFdO1hAueZLc= github.com/go-interpreter/wagon v0.6.0/go.mod h1:5+b/MBYkclRZngKF5s6qrgWxSLgE9F5dFdO1hAueZLc= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/gddo v0.0.0-20190815223733-287de01127ef/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 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.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo= @@ -36,22 +75,44 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI github.com/google/pprof v0.0.0-20190908185732-236ed259b199/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jmoiron/sqlx v0.0.0-20150110152746-69738bd20981/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/knq/sysutil v0.0.0-20181215143952-f05b59f0f307/go.mod h1:BjPj+aVjl9FW/cCGiF3nGh5v+9Gd3VCgBQbod/GlMaQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 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= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190403194419-1ea4449da983/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190620125010-da37f6c1e481/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -62,15 +123,38 @@ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nullrocks/identicon v0.0.0-20180626043057-7875f45b0022 h1:Ys0rDzh8s4UMlGaDa1UTA0sfKgvF0hQZzTYX8ktjiDc= github.com/nullrocks/identicon v0.0.0-20180626043057-7875f45b0022/go.mod h1:x4NsS+uc7ecH/Cbm9xKQ6XzmJM57rWTkjywjfB2yQ18= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.5.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.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= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= @@ -78,27 +162,52 @@ github.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs= github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= +github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20170602164621-9e8dc3f972df/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sour-is/crypto v0.0.0-20201016232853-f42a24ba5a81 h1:7LadZJfye3tq1Dr5c46uy1ign6mQr2bAOlCJeAXpB1A= github.com/sour-is/crypto v0.0.0-20201016232853-f42a24ba5a81/go.mod h1:7/Of5cnNodFyJ6PH2C3STkdCRvqbhj9yA3BhQ/E62wA= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 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/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 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 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/zbase32 v0.0.0-20190604154422-aacc64a8f915 h1:vX9DBbEHmrebYnVthUTzMO6Zc1vvConJdD2s0uvXrfw= github.com/tv42/zbase32 v0.0.0-20190604154422-aacc64a8f915/go.mod h1:Y5DJgF9Eou+hSWetC39Mns8E0PU7DykCLNWiYeOINrE= github.com/twitchyliquid64/golang-asm v0.0.0-20190126203739-365674df15fc/go.mod h1:NoCfSFWosfqMqmmD7hApkirIK9ozpHjxRnRxs1l413A= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U= +github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yosssi/gmq v0.0.1/go.mod h1:mReykazh0U1JabvuWh1PEbzzJftqOQWsjr0Lwg5jL1Y= go.coder.com/go-tools v0.0.0-20190317003359-0c6a35b74a16/go.mod h1:iKV5yK9t+J5nG9O3uF6KYdPEz3dyfMyB15MN1rbQ8Qw= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= @@ -109,7 +218,9 @@ go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/ratelimit v0.1.0 h1:U2AruXqeTb4Eh9sYQSTrMhH8Cb7M0Ian2ibBOnBcnAw= go.uber.org/ratelimit v0.1.0/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180426230345-b49d69b5da94/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9 h1:phUcVbl53swtrUN8kQEXFhUxPlIlWyBfKmidCu7P95o= @@ -118,21 +229,34 @@ golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 h1:xYJJ3S178yv++9zXV/hnr2 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/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-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/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-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190306220234-b354f8bf4d9e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -142,40 +266,59 @@ golang.org/x/sys v0.0.0-20190618155005-516e3c20635f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190927073244-c990c680b611/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 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.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 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.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gosrc.io/xmpp v0.5.1 h1:Rgrm5s2rt+npGggJH3HakQxQXR8ZZz3+QRzakRQqaq4= gosrc.io/xmpp v0.5.1/go.mod h1:L3NFMqYOxyLz3JGmgFyWf7r9htE91zVGiK40oW4RwdY= gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/gotestsum v0.3.5/go.mod h1:Mnf3e5FUzXbkCfynWBGOwLssY7gTQgCHObK9tMpAriY= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= mvdan.cc/sh v2.6.4+incompatible/go.mod h1:IeeQbZq+x2SUGBensq/jge5lLQbS3XT2ktyp3wrt4x8= nhooyr.io/websocket v1.6.5 h1:8TzpkldRfefda5JST+CnOH135bzVPz5uzfn/AF+gVKg= nhooyr.io/websocket v1.6.5/go.mod h1:F259lAzPRAH0htX2y3ehpJe09ih1aSHN7udWki1defY= +sour.is/x/toolbox v0.12.17 h1:m+8fAl5dkuu2HsmkOuefb6tDFzpPq93xAAtZZvBxySk= +sour.is/x/toolbox v0.12.17/go.mod h1:DMM+aEl38izskLKuH+nDwEHH4FznK6dEiDcPR3wAq5s= +sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= +sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k= diff --git a/main.go b/main.go index 245408b..14d18a5 100644 --- a/main.go +++ b/main.go @@ -15,16 +15,24 @@ import ( "github.com/rs/cors" "github.com/rs/zerolog" "github.com/rs/zerolog/log" - "gosrc.io/xmpp" "github.com/sour-is/keyproofs/pkg/cache" "github.com/sour-is/keyproofs/pkg/config" "github.com/sour-is/keyproofs/pkg/graceful" - "github.com/sour-is/keyproofs/pkg/keyproofs" + "github.com/sour-is/keyproofs/pkg/httpsrv" + + app_avatar "github.com/sour-is/keyproofs/pkg/app/avatar" + app_dns "github.com/sour-is/keyproofs/pkg/app/dns" + app_keyproofs "github.com/sour-is/keyproofs/pkg/app/keyproofs" + app_vcard "github.com/sour-is/keyproofs/pkg/app/vcard" + app_wkd "github.com/sour-is/keyproofs/pkg/app/wkd" ) var ( + // AppName Application Name + AppName string = "KeyProofs" + // AppVersion Application Version Number AppVersion string @@ -48,14 +56,21 @@ func main() { ctx, _ = graceful.WithWaitGroup(ctx) cfg := config.New() - cfg.Set("app-name", "KeyProofs") + cfg.Set("app-name", AppName) cfg.Set("app-version", AppVersion) cfg.Set("build-hash", BuildHash) cfg.Set("build-date", BuildDate) ctx = cfg.Apply(ctx) + log.Info(). + Str("app", AppName). + Str("version", AppVersion). + Str("build-hash", BuildHash). + Str("build-date", BuildDate). + Msg("startup...") + if err := run(ctx); err != nil { - log.Error().Stack().Err(err).Msg("Application Failed") + log.Error().Err(err).Msg("Application Failed") os.Exit(1) } } @@ -63,6 +78,7 @@ func main() { func run(ctx context.Context) error { log := log.Ctx(ctx) wg := graceful.WaitGroup(ctx) + cfg := config.FromContext(ctx) // derive baseURL from listener options listen := env("HTTP_LISTEN", ":9061") @@ -72,89 +88,83 @@ func run(ctx context.Context) error { } baseURL := fmt.Sprintf("http://%s", host) - // Set config values - cfg := config.FromContext(ctx) - cfg.Set("base-url", env("BASE_URL", baseURL)) - cfg.Set("dns-url", env("DNS_URL", baseURL)) - cfg.Set("xmpp-url", env("XMPP_URL", baseURL)) - - cfg.Set("reddit.api-key", os.Getenv("REDDIT_APIKEY")) - cfg.Set("reddit.secret", os.Getenv("REDDIT_SECRET")) - - cfg.Set("xmpp-config", &xmpp.Config{ - Jid: os.Getenv("XMPP_USERNAME"), - Credential: xmpp.Password(os.Getenv("XMPP_PASSWORD")), + // Setup router + cors := cors.New(cors.Options{ + AllowCredentials: true, + AllowedMethods: strings.Fields(env("CORS_METHODS", "GET")), + AllowedOrigins: strings.Fields(env("CORS_ORIGIN", "*")), }) + logFmt := &middleware.DefaultLogFormatter{Logger: accessLog(log.Info)} + mux := chi.NewRouter() mux.Use( - cfg.ApplyHTTP, - func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - r = r.WithContext(log.WithContext(r.Context())) - next.ServeHTTP(w, r) - }) - }, - secHeaders, - cors.New(cors.Options{ - AllowCredentials: true, - AllowedMethods: strings.Fields(env("CORS_METHODS", "GET")), - AllowedOrigins: strings.Fields(env("CORS_ORIGIN", "*")), - }).Handler, middleware.RequestID, middleware.RealIP, - middleware.RequestLogger(&middleware.DefaultLogFormatter{Logger: accessLog(log.Info)}), middleware.Recoverer, + middleware.RequestLogger(logFmt), + secHeaders, + cors.Handler, + addLogger(log), + cfg.ApplyHTTP, ) if env("DISABLE_KEYPROOF", "false") == "false" { + // Set config values + cfg.Set("base-url", env("BASE_URL", baseURL)) + cfg.Set("dns-url", env("DNS_URL", baseURL)) + cfg.Set("xmpp-url", env("XMPP_URL", baseURL)) + + cfg.Set("reddit.api-key", os.Getenv("REDDIT_APIKEY")) + cfg.Set("reddit.secret", os.Getenv("REDDIT_SECRET")) + cfg.Set("github.secret", os.Getenv("GITHUB_SECRET")) + // Create cache for promise engine arc, _ := lru.NewARC(4096) c := cache.New(arc) - keyproofs.NewKeyProofApp(ctx, c).Routes(mux) + app_keyproofs.NewKeyProofApp(ctx, c).Routes(mux) } if env("DISABLE_DNS", "false") == "false" { - keyproofs.NewDNSApp(ctx).Routes(mux) + app_dns.New(ctx).Routes(mux) } if env("DISABLE_AVATAR", "false") == "false" { - avatarApp, err := keyproofs.NewAvatarApp(ctx, env("AVATAR_PATH", "pub")) + app, err := app_avatar.New(ctx, env("AVATAR_PATH", "pub")) if err != nil { return err } - avatarApp.Routes(mux) + app.Routes(mux) } if env("DISABLE_WKD", "false") == "false" { - avatarApp, err := keyproofs.NewWKDApp(ctx, env("WKD_PATH", "pub"), env("WKD_DOMAIN", "pub")) + app, err := app_wkd.New(ctx, env("WKD_PATH", "pub"), env("WKD_DOMAIN", "pub")) if err != nil { return err } - avatarApp.Routes(mux) + app.Routes(mux) } if env("DISABLE_VCARD", "false") == "false" { - vcardApp, err := keyproofs.NewVCardApp(ctx) + app, err := app_vcard.New(ctx, &xmpp.Config{ + Jid: os.Getenv("XMPP_USERNAME"), + Credential: xmpp.Password(os.Getenv("XMPP_PASSWORD")), + }) if err != nil { return err } - vcardApp.Routes(mux) + app.Routes(mux) } log.Info(). - Str("app", cfg.GetString("app-name")). - Str("version", cfg.GetString("app-version")). - Str("build-hash", cfg.GetString("build-hash")). - Str("build-date", cfg.GetString("build-date")). Str("listen", listen). Int("user", os.Geteuid()). Int("group", os.Getgid()). - Msg("startup") + Msg("running") - err := New(&http.Server{ + err := httpsrv.New(&http.Server{ Addr: listen, WriteTimeout: 15 * time.Second, ReadTimeout: 15 * time.Second, @@ -167,41 +177,6 @@ func run(ctx context.Context) error { return wg.Wait(5 * time.Second) } -type Server struct { - srv *http.Server -} - -func New(s *http.Server) *Server { - return &Server{srv: s} -} -func (s *Server) Run(ctx context.Context) error { - log := log.Ctx(ctx) - wg := graceful.WaitGroup(ctx) - - wg.Go(func() error { - <-ctx.Done() - log.Info().Msg("Shutdown HTTP") - - ctx := context.Background() - ctx, cancel := context.WithTimeout(ctx, 10*time.Second) - defer cancel() - err := s.srv.Shutdown(ctx) - if err != nil && err != http.ErrServerClosed { - return err - } - - log.Info().Msg("Stopped HTTP") - return nil - }) - - err := s.srv.ListenAndServe() - if err != nil && err != http.ErrServerClosed { - return err - } - - return nil -} - func env(name, defaultValue string) string { if value := os.Getenv(name); value != "" { return value @@ -227,3 +202,12 @@ type accessLog func() *zerolog.Event func (a accessLog) Print(v ...interface{}) { a().Msg(fmt.Sprint(v...)) } + +func addLogger(log *zerolog.Logger) func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + r = r.WithContext(log.WithContext(r.Context())) + next.ServeHTTP(w, r) + }) + } +} diff --git a/pkg/keyproofs/routes-avatar.go b/pkg/app/avatar/avatar.go similarity index 88% rename from pkg/keyproofs/routes-avatar.go rename to pkg/app/avatar/avatar.go index 40a6683..addb797 100644 --- a/pkg/keyproofs/routes-avatar.go +++ b/pkg/app/avatar/avatar.go @@ -1,4 +1,4 @@ -package keyproofs +package app_avatar import ( "context" @@ -21,17 +21,20 @@ import ( "github.com/rs/zerolog/log" "github.com/sour-is/keyproofs/pkg/graceful" + "github.com/sour-is/keyproofs/pkg/style" ) -type avatarApp struct { +var pixl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" + +type avatar struct { path string } -func NewAvatarApp(ctx context.Context, path string) (*avatarApp, error) { +func New(ctx context.Context, path string) (*avatar, error) { log := log.Ctx(ctx) path = filepath.Clean(path) - app := &avatarApp{path: path} + app := &avatar{path: path} err := app.CheckFiles(ctx) if err != nil { return nil, fmt.Errorf("check files: %w", err) @@ -84,7 +87,7 @@ func NewAvatarApp(ctx context.Context, path string) (*avatarApp, error) { return app, nil } -func (app *avatarApp) CheckFiles(ctx context.Context) error { +func (app *avatar) CheckFiles(ctx context.Context) error { log := log.Ctx(ctx) for _, name := range []string{".links", "avatar", "bg", "cover"} { @@ -118,7 +121,7 @@ func (app *avatarApp) CheckFiles(ctx context.Context) error { }) } -func (app *avatarApp) get(w http.ResponseWriter, r *http.Request) { +func (app *avatar) get(w http.ResponseWriter, r *http.Request) { log := log.Ctx(r.Context()) log.Print(r.Host) @@ -133,7 +136,7 @@ func (app *avatarApp) get(w http.ResponseWriter, r *http.Request) { log.Debug().Int("width", sizeW).Int("height", sizeH).Bool("resize", resize).Str("kind", kind).Msg("Get Image") if strings.ContainsRune(hash, '@') { - avatarHost, _, err := styleSRV(r.Context(), hash) + avatarHost, _, err := style.GetSRV(r.Context(), hash) if err != nil { writeText(w, 500, err.Error()) return @@ -213,7 +216,7 @@ func (app *avatarApp) get(w http.ResponseWriter, r *http.Request) { } } -func (app *avatarApp) Routes(r *chi.Mux) { +func (app *avatar) Routes(r *chi.Mux) { r.MethodFunc("GET", "/{kind:avatar|bg|cover}/{hash}", app.get) } @@ -228,7 +231,7 @@ func hashSHA256(name string) string { return hashString(name, sha256.New()) } -func (app *avatarApp) createLinks(kind, name string) error { +func (app *avatar) createLinks(kind, name string) error { if !strings.ContainsRune(name, '@') { return nil } @@ -250,7 +253,7 @@ func (app *avatarApp) createLinks(kind, name string) error { return err } -func (app *avatarApp) removeLinks(kind, name string) error { +func (app *avatar) removeLinks(kind, name string) error { if !strings.ContainsRune(name, '@') { return nil } @@ -270,7 +273,7 @@ func (app *avatarApp) removeLinks(kind, name string) error { return err } -func (app *avatarApp) replaceLink(src, link string) error { +func (app *avatar) replaceLink(src, link string) error { if dst, err := os.Readlink(link); err != nil { if os.IsNotExist(err) { err = os.Symlink(src, link) @@ -342,3 +345,10 @@ func clamp(min, max, size int) int { return size } + +// WriteText writes plain text +func writeText(w http.ResponseWriter, code int, o string) { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(code) + _, _ = w.Write([]byte(o)) +} diff --git a/pkg/app/dns/dns.go b/pkg/app/dns/dns.go new file mode 100644 index 0000000..82f5709 --- /dev/null +++ b/pkg/app/dns/dns.go @@ -0,0 +1,37 @@ +package app_dns + +import ( + "context" + "fmt" + "net" + "net/http" + "strings" + + "github.com/go-chi/chi" +) + +type app struct { + resolver *net.Resolver +} + +func New(ctx context.Context) *app { + return &app{resolver: net.DefaultResolver} +} +func (app *app) getDNS(w http.ResponseWriter, r *http.Request) { + domain := chi.URLParam(r, "domain") + + w.Header().Set("Content-Type", "text/plain") + + res, err := app.resolver.LookupTXT(r.Context(), domain) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + + fmt.Fprintln(w, err) + return + } + + fmt.Fprintln(w, strings.Join(res, "\n")) +} +func (app *app) Routes(r *chi.Mux) { + r.MethodFunc("GET", "/dns/{domain}", app.getDNS) +} diff --git a/pkg/keyproofs/routes-keyproofs.go b/pkg/app/keyproofs/app.go similarity index 89% rename from pkg/keyproofs/routes-keyproofs.go rename to pkg/app/keyproofs/app.go index 9d9fe15..114b493 100644 --- a/pkg/keyproofs/routes-keyproofs.go +++ b/pkg/app/keyproofs/app.go @@ -1,4 +1,4 @@ -package keyproofs +package app_keyproofs import ( "context" @@ -16,7 +16,10 @@ import ( "github.com/sour-is/keyproofs/pkg/cache" "github.com/sour-is/keyproofs/pkg/config" + "github.com/sour-is/keyproofs/pkg/opgp" + "github.com/sour-is/keyproofs/pkg/opgp/entity" "github.com/sour-is/keyproofs/pkg/promise" + "github.com/sour-is/keyproofs/pkg/style" ) var expireAfter = 20 * time.Minute @@ -26,11 +29,11 @@ var runnerTimeout = 30 * time.Second var pixl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" var keypng, _ = base64.StdEncoding.DecodeString("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABKUlEQVQ4jZ2SvUoDURCFUy/Y2Fv4BoKIiFgLSWbmCWw0e3cmNgGfwacQsbCxUEFEEIVkxsQulaK1kheIiFVW1mJXiZv904FbXb5zzvzUaiWlPqyYwIkyvRjjqwmeaauxUcbFMKOvTKEJRVPv05hCY9wrhHt+fckEJ79gxg9rweJN8qdSkESZjlLOkQm+Xe9szlubFkxwYoznuQIm9DgrQJEyjZXpPU5Eo6L+H7IEUmJFAnBQJmAMp5nw0IFnjFoiEGrQXJuBLx14JtgtiR5qAO2c4aFLAffGeGiMT8b0rAEe96WxnBlbGbbia/vZ+2CwjXO5g0pN/TZ1NNXgoQPPHO2aJLsViu4E+xdVnXsOOtPOMbxeDY6jw/6/nL+r6+qryjQyhqs/OSf1Bf+pJC1wKqO/AAAAAElFTkSuQmCC") -var defaultStyle = &Style{ +var defaultStyle = &style.Style{ Avatar: pixl, Cover: pixl, Background: pixl, - Palette: getPalette("#93CCEA"), + Palette: style.GetPalette("#93CCEA"), } type keyproofApp struct { @@ -70,24 +73,24 @@ func (app *keyproofApp) getProofs(w http.ResponseWriter, r *http.Request) { defer cancel() // Run tasks to resolve entity, style, and proofs. - task := app.tasker.Run(EntityKey(id), func(q promise.Q) { + task := app.tasker.Run(entity.Key(id), func(q promise.Q) { ctx := q.Context() log := zlog.Ctx(ctx).With().Interface(fmtKey(q), q.Key()).Logger() - key := q.Key().(EntityKey) + key := q.Key().(entity.Key) - entity, err := getOpenPGPkey(ctx, string(key)) + e, err := opgp.GetKey(ctx, string(key)) if err != nil { q.Reject(err) return } log.Debug().Msg("Resolving Entity") - q.Resolve(entity) + q.Resolve(e) }) task.After(func(q promise.ResultQ) { - entity := q.Result().(*Entity) + entity := q.Result().(*entity.Entity) zlog.Ctx(q.Context()). Info(). @@ -95,14 +98,14 @@ func (app *keyproofApp) getProofs(w http.ResponseWriter, r *http.Request) { Interface(fmtKey(q), q.Key()). Msg("Do Style ") - q.Run(StyleKey(entity.Primary.Address), func(q promise.Q) { + q.Run(style.Key(entity.Primary.Address), func(q promise.Q) { ctx := q.Context() log := zlog.Ctx(ctx).With().Interface(fmtKey(q), q.Key()).Logger() - key := q.Key().(StyleKey) + key := q.Key().(style.Key) log.Debug().Msg("start task") - style, err := getStyle(ctx, string(key)) + style, err := style.GetStyle(ctx, string(key)) if err != nil { q.Reject(err) return @@ -114,7 +117,7 @@ func (app *keyproofApp) getProofs(w http.ResponseWriter, r *http.Request) { }) task.After(func(q promise.ResultQ) { - entity := q.Result().(*Entity) + entity := q.Result().(*entity.Entity) log := zlog.Ctx(ctx). With(). Interface(fmtKey(q), q.Key()). @@ -158,12 +161,12 @@ func (app *keyproofApp) getProofs(w http.ResponseWriter, r *http.Request) { page.IsComplete = true break } - page.Entity = task.Result().(*Entity) + page.Entity = task.Result().(*entity.Entity) case <-ctx.Done(): log.Print("Deadline Timeout") - if e, ok := app.cache.Get(EntityKey(id)); ok { - page.Entity = e.Value().(*Entity) + if e, ok := app.cache.Get(entity.Key(id)); ok { + page.Entity = e.Value().(*entity.Entity) } } @@ -171,8 +174,8 @@ func (app *keyproofApp) getProofs(w http.ResponseWriter, r *http.Request) { if page.Entity != nil { var gotStyle, gotProofs bool - if s, ok := app.cache.Get(StyleKey(page.Entity.Primary.Address)); ok { - page.Style = s.Value().(*Style) + if s, ok := app.cache.Get(style.Key(page.Entity.Primary.Address)); ok { + page.Style = s.Value().(*style.Style) gotStyle = true } diff --git a/pkg/keyproofs/proofs.go b/pkg/app/keyproofs/proofs.go similarity index 99% rename from pkg/keyproofs/proofs.go rename to pkg/app/keyproofs/proofs.go index 2e4af50..244edd8 100644 --- a/pkg/keyproofs/proofs.go +++ b/pkg/app/keyproofs/proofs.go @@ -1,4 +1,4 @@ -package keyproofs +package app_keyproofs import ( "bufio" diff --git a/pkg/keyproofs/template.go b/pkg/app/keyproofs/template.go similarity index 97% rename from pkg/keyproofs/template.go rename to pkg/app/keyproofs/template.go index 68124e6..84425be 100644 --- a/pkg/keyproofs/template.go +++ b/pkg/app/keyproofs/template.go @@ -1,10 +1,15 @@ -package keyproofs +package app_keyproofs + +import ( + "github.com/sour-is/keyproofs/pkg/opgp/entity" + "github.com/sour-is/keyproofs/pkg/style" +) type page struct { AppName string AppBuild string - Entity *Entity - Style *Style + Entity *entity.Entity + Style *style.Style Proofs *Proofs Markdown string @@ -228,7 +233,11 @@ var proofTPL = `
Public Key
-
{{.Entity.ArmorText}}
+

+Last Updated {{.Entity.SelfSignature.CreationTime}}
+
+{{.Entity.ArmorText}}
+
diff --git a/pkg/app/vcard/app.go b/pkg/app/vcard/app.go new file mode 100644 index 0000000..fc2facd --- /dev/null +++ b/pkg/app/vcard/app.go @@ -0,0 +1,48 @@ +package app_vcard + +import ( + "context" + "fmt" + "net/http" + "net/mail" + + "github.com/go-chi/chi" + "gosrc.io/xmpp" +) + +type app struct { + conn *connection +} + +func New(ctx context.Context, xmppConfig *xmpp.Config) (*app, error) { + conn, err := NewXMPP(ctx, xmppConfig) + if err != nil { + return nil, err + } + + return &app{conn: conn}, nil +} +func (app *app) Routes(r *chi.Mux) { + r.MethodFunc("GET", "/vcard/{jid}", app.getVCard) +} +func (app *app) getVCard(w http.ResponseWriter, r *http.Request) { + jid := chi.URLParam(r, "jid") + if _, err := mail.ParseAddress(jid); err != nil { + w.WriteHeader(http.StatusBadRequest) + fmt.Fprint(w, err) + + return + } + + vcard, err := app.conn.GetXMPPVCard(r.Context(), jid) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprint(w, err) + + return + } + + w.Header().Set("Content-Type", "text/xml") + w.WriteHeader(200) + fmt.Fprint(w, vcard) +} diff --git a/pkg/app/vcard/vcard.go b/pkg/app/vcard/vcard.go new file mode 100644 index 0000000..dde2c39 --- /dev/null +++ b/pkg/app/vcard/vcard.go @@ -0,0 +1,36 @@ +package app_vcard + +import ( + "encoding/xml" + + "gosrc.io/xmpp/stanza" +) + +type VCard struct { + XMLName xml.Name `xml:"vcard-temp vCard"` + FullName string `xml:"FN"` + NickName string `xml:"NICKNAME"` + Description string `xml:"DESC"` + URL string `xml:"URL"` +} + +func NewVCard() *VCard { + return &VCard{} +} + +func (c *VCard) Namespace() string { + return c.XMLName.Space +} + +func (c *VCard) GetSet() *stanza.ResultSet { + return nil +} + +func (c *VCard) String() string { + b, _ := xml.MarshalIndent(c, "", " ") + return string(b) +} + +func init() { + stanza.TypeRegistry.MapExtension(stanza.PKTIQ, xml.Name{Space: "vcard-temp", Local: "vCard"}, VCard{}) +} diff --git a/pkg/keyproofs/vcard.go b/pkg/app/vcard/xmpp.go similarity index 71% rename from pkg/keyproofs/vcard.go rename to pkg/app/vcard/xmpp.go index 4019a5d..45e286d 100644 --- a/pkg/keyproofs/vcard.go +++ b/pkg/app/vcard/xmpp.go @@ -1,4 +1,4 @@ -package keyproofs +package app_vcard import ( "context" @@ -11,35 +11,6 @@ import ( "gosrc.io/xmpp/stanza" ) -type VCard struct { - XMLName xml.Name `xml:"vcard-temp vCard"` - FullName string `xml:"FN"` - NickName string `xml:"NICKNAME"` - Description string `xml:"DESC"` - URL string `xml:"URL"` -} - -func NewVCard() *VCard { - return &VCard{} -} - -func (c *VCard) Namespace() string { - return c.XMLName.Space -} - -func (c *VCard) GetSet() *stanza.ResultSet { - return nil -} - -func (c *VCard) String() string { - b, _ := xml.MarshalIndent(c, "", " ") - return string(b) -} - -func init() { - stanza.TypeRegistry.MapExtension(stanza.PKTIQ, xml.Name{Space: "vcard-temp", Local: "vCard"}, VCard{}) -} - type connection struct { client xmpp.StreamClient } diff --git a/pkg/keyproofs/routes-wkd.go b/pkg/app/wkd/app.go similarity index 91% rename from pkg/keyproofs/routes-wkd.go rename to pkg/app/wkd/app.go index e06ba67..3482252 100644 --- a/pkg/keyproofs/routes-wkd.go +++ b/pkg/app/wkd/app.go @@ -1,4 +1,4 @@ -package keyproofs +package app_wkd import ( "context" @@ -17,8 +17,10 @@ import ( "github.com/go-chi/chi" "github.com/rs/zerolog/log" "github.com/sour-is/crypto/openpgp" - "github.com/sour-is/keyproofs/pkg/graceful" "github.com/tv42/zbase32" + + "github.com/sour-is/keyproofs/pkg/graceful" + "github.com/sour-is/keyproofs/pkg/opgp/entity" ) type wkdApp struct { @@ -26,7 +28,7 @@ type wkdApp struct { domain string } -func NewWKDApp(ctx context.Context, path, domain string) (*wkdApp, error) { +func New(ctx context.Context, path, domain string) (*wkdApp, error) { log := log.Ctx(ctx) log.Debug().Str("domain", domain).Str("path", path).Msg("NewWKDApp") @@ -291,7 +293,7 @@ func (app *wkdApp) postKey(w http.ResponseWriter, r *http.Request) { return } - entity, err := getEntity(lis) + e, err := entity.GetOne(lis) if err != nil { log.Err(err).Send() writeText(w, http.StatusBadRequest, "ERR ENTITY") @@ -299,7 +301,7 @@ func (app *wkdApp) postKey(w http.ResponseWriter, r *http.Request) { return } - fname := filepath.Join(app.path, "keys", entity.Primary.Address) + fname := filepath.Join(app.path, "keys", e.Primary.Address) f, err := os.Open(fname) if os.IsNotExist(err) { @@ -311,7 +313,7 @@ func (app *wkdApp) postKey(w http.ResponseWriter, r *http.Request) { return } - err = entity.Serialize(out) + err = e.Serialize(out) if err != nil { log.Err(err).Send() writeText(w, http.StatusInternalServerError, "ERR WRITE") @@ -332,7 +334,7 @@ func (app *wkdApp) postKey(w http.ResponseWriter, r *http.Request) { } f.Close() - compare, err := getEntity(current) + compare, err := entity.GetOne(current) if err != nil { log.Err(err).Send() writeText(w, http.StatusInternalServerError, "ERR PARSE") @@ -340,20 +342,20 @@ func (app *wkdApp) postKey(w http.ResponseWriter, r *http.Request) { return } - if entity.Fingerprint != compare.Fingerprint { + if e.Fingerprint != compare.Fingerprint { w.Header().Set("X-HKP-Status", "Mismatch fingerprint") writeText(w, http.StatusBadRequest, "ERR FINGERPRINT") return } - if entity.SelfSignature == nil || compare.SelfSignature == nil { + if e.SelfSignature == nil || compare.SelfSignature == nil { w.Header().Set("X-HKP-Status", "Missing signature") writeText(w, http.StatusBadRequest, "ERR SIGNATURE") return } - log.Debug().Msgf("%v < %v", entity.SelfSignature.CreationTime, compare.SelfSignature.CreationTime) + log.Debug().Msgf("%v < %v", e.SelfSignature.CreationTime, compare.SelfSignature.CreationTime) - if !compare.SelfSignature.CreationTime.Before(entity.SelfSignature.CreationTime) { + if !compare.SelfSignature.CreationTime.Before(e.SelfSignature.CreationTime) { w.Header().Set("X-HKP-Status", "out of date") writeText(w, http.StatusBadRequest, "ERR OUT OF DATE") @@ -368,7 +370,7 @@ func (app *wkdApp) postKey(w http.ResponseWriter, r *http.Request) { return } - err = entity.Serialize(out) + err = e.Serialize(out) if err != nil { log.Err(err).Send() writeText(w, http.StatusInternalServerError, "ERR WRITE") @@ -379,3 +381,10 @@ func (app *wkdApp) postKey(w http.ResponseWriter, r *http.Request) { w.Header().Set("X-HKP-Status", "Updated key") writeText(w, http.StatusOK, "OK UPDATED") } + +// WriteText writes plain text +func writeText(w http.ResponseWriter, code int, o string) { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(code) + _, _ = w.Write([]byte(o)) +} diff --git a/pkg/httpsrv/server.go b/pkg/httpsrv/server.go new file mode 100644 index 0000000..161196f --- /dev/null +++ b/pkg/httpsrv/server.go @@ -0,0 +1,46 @@ +package httpsrv + +import ( + "context" + "net/http" + "time" + + "github.com/rs/zerolog/log" + "github.com/sour-is/keyproofs/pkg/graceful" +) + +type Server struct { + srv *http.Server +} + +func New(s *http.Server) *Server { + + return &Server{srv: s} +} +func (s *Server) Run(ctx context.Context) error { + log := log.Ctx(ctx) + wg := graceful.WaitGroup(ctx) + + wg.Go(func() error { + <-ctx.Done() + log.Info().Msg("Shutdown HTTP") + + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + err := s.srv.Shutdown(ctx) + if err != nil && err != http.ErrServerClosed { + return err + } + + log.Info().Msg("Stopped HTTP") + return nil + }) + + err := s.srv.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + return err + } + + return nil +} diff --git a/pkg/keyproofs/routes-dns.go b/pkg/keyproofs/routes-dns.go deleted file mode 100644 index 0ab8a7d..0000000 --- a/pkg/keyproofs/routes-dns.go +++ /dev/null @@ -1,32 +0,0 @@ -package keyproofs - -import ( - "context" - "net" - "net/http" - "strings" - - "github.com/go-chi/chi" -) - -type dnsApp struct { - resolver *net.Resolver -} - -func NewDNSApp(ctx context.Context) *dnsApp { - return &dnsApp{resolver: net.DefaultResolver} -} -func (app *dnsApp) getDNS(w http.ResponseWriter, r *http.Request) { - domain := chi.URLParam(r, "domain") - - res, err := app.resolver.LookupTXT(r.Context(), domain) - if err != nil { - writeText(w, 400, err.Error()) - return - } - - writeText(w, 200, strings.Join(res, "\n")) -} -func (app *dnsApp) Routes(r *chi.Mux) { - r.MethodFunc("GET", "/dns/{domain}", app.getDNS) -} diff --git a/pkg/keyproofs/routes-vcard.go b/pkg/keyproofs/routes-vcard.go deleted file mode 100644 index 2a196f6..0000000 --- a/pkg/keyproofs/routes-vcard.go +++ /dev/null @@ -1,56 +0,0 @@ -package keyproofs - -import ( - "context" - "fmt" - "net/http" - "net/mail" - - "github.com/go-chi/chi" - zlog "github.com/rs/zerolog/log" - "github.com/sour-is/keyproofs/pkg/config" - "gosrc.io/xmpp" -) - -type vcardApp struct { - conn *connection -} - -func NewVCardApp(ctx context.Context) (*vcardApp, error) { - log := zlog.Ctx(ctx) - - var ok bool - var xmppConfig *xmpp.Config - if xmppConfig, ok = config.FromContext(ctx).Get("xmpp-config").(*xmpp.Config); !ok { - log.Error().Msg("no xmpp-config") - - return nil, fmt.Errorf("no xmpp config") - } - - conn, err := NewXMPP(ctx, xmppConfig) - if err != nil { - return nil, err - } - - return &vcardApp{conn: conn}, nil -} -func (app *vcardApp) Routes(r *chi.Mux) { - r.MethodFunc("GET", "/vcard/{jid}", app.getVCard) -} -func (app *vcardApp) getVCard(w http.ResponseWriter, r *http.Request) { - jid := chi.URLParam(r, "jid") - if _, err := mail.ParseAddress(jid); err != nil { - fmt.Fprint(w, err) - w.WriteHeader(400) - } - - vcard, err := app.conn.GetXMPPVCard(r.Context(), jid) - if err != nil { - fmt.Fprint(w, err) - w.WriteHeader(500) - } - - w.Header().Set("Content-Type", "text/xml") - w.WriteHeader(200) - fmt.Fprint(w, vcard) -} diff --git a/pkg/opgp/entity/entity.go b/pkg/opgp/entity/entity.go new file mode 100644 index 0000000..4ed5f26 --- /dev/null +++ b/pkg/opgp/entity/entity.go @@ -0,0 +1,89 @@ +package entity + +import ( + "fmt" + "io" + "net/mail" + + "github.com/sour-is/crypto/openpgp" + "github.com/sour-is/crypto/openpgp/packet" +) + +type Key string + +func (k Key) Key() interface{} { + return k +} + +type Entity struct { + Primary *mail.Address + SelfSignature *packet.Signature + Emails []*mail.Address + Fingerprint string + Proofs []string + ArmorText string + entity *openpgp.Entity +} + +func (e *Entity) Serialize(f io.Writer) error { + return e.entity.Serialize(f) +} + +func GetOne(lis openpgp.EntityList) (*Entity, error) { + entity := &Entity{} + var err error + + for _, e := range lis { + if e == nil { + continue + } + if e.PrimaryKey == nil { + continue + } + + entity.entity = e + entity.Fingerprint = fmt.Sprintf("%X", e.PrimaryKey.Fingerprint) + + for name, ident := range e.Identities { + // Pick first identity + if entity.Primary == nil { + entity.Primary, err = mail.ParseAddress(name) + if err != nil { + return entity, err + } + } + // If one is marked primary use that + if ident.SelfSignature != nil && ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { + entity.Primary, err = mail.ParseAddress(name) + if err != nil { + return entity, err + } + + } else { + var email *mail.Address + if email, err = mail.ParseAddress(name); err != nil { + return entity, err + } + if email.Address != entity.Primary.Address { + entity.Emails = append(entity.Emails, email) + } + } + + // If identity is self signed read notation data. + if ident.SelfSignature != nil && ident.SelfSignature.NotationData != nil { + entity.SelfSignature = ident.SelfSignature + // Get proofs and append to list. + if proofs, ok := ident.SelfSignature.NotationData["proof@metacode.biz"]; ok { + entity.Proofs = append(entity.Proofs, proofs...) + } + } + } + break + } + + if entity.Primary == nil { + entity.Primary, _ = mail.ParseAddress("nobody@nodomain.xyz") + } + + return entity, err +} diff --git a/pkg/keyproofs/opengpg.go b/pkg/opgp/util.go similarity index 57% rename from pkg/keyproofs/opengpg.go rename to pkg/opgp/util.go index 8f49d6f..47ab1bb 100644 --- a/pkg/keyproofs/opengpg.go +++ b/pkg/opgp/util.go @@ -1,4 +1,4 @@ -package keyproofs +package opgp import ( "bytes" @@ -13,12 +13,12 @@ import ( "github.com/rs/zerolog/log" "github.com/sour-is/crypto/openpgp" - "github.com/sour-is/crypto/openpgp/packet" + "github.com/sour-is/keyproofs/pkg/opgp/entity" "github.com/tv42/zbase32" "golang.org/x/crypto/openpgp/armor" ) -func getOpenPGPkey(ctx context.Context, id string) (entity *Entity, err error) { +func GetKey(ctx context.Context, id string) (entity *entity.Entity, err error) { if isFingerprint(id) { addr := "https://keys.openpgp.org/vks/v1/by-fingerprint/" + strings.ToUpper(id) return getEntityHTTP(ctx, addr, true) @@ -41,7 +41,7 @@ func getOpenPGPkey(ctx context.Context, id string) (entity *Entity, err error) { } } -func getEntityHTTP(ctx context.Context, url string, useArmored bool) (entity *Entity, err error) { +func getEntityHTTP(ctx context.Context, url string, useArmored bool) (entity *entity.Entity, err error) { log := log.Ctx(ctx) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) @@ -72,90 +72,11 @@ func getEntityHTTP(ctx context.Context, url string, useArmored bool) (entity *En return ReadKey(resp.Body, useArmored) } -type EntityKey string - -func (k EntityKey) Key() interface{} { - return k -} - -type Entity struct { - Primary *mail.Address - SelfSignature *packet.Signature - Emails []*mail.Address - Fingerprint string - Proofs []string - ArmorText string - entity *openpgp.Entity -} - -func (e *Entity) Serialize(f io.Writer) error { - return e.entity.Serialize(f) -} - -func getEntity(lis openpgp.EntityList) (*Entity, error) { - entity := &Entity{} - var err error - - for _, e := range lis { - if e == nil { - continue - } - if e.PrimaryKey == nil { - continue - } - - entity.entity = e - entity.Fingerprint = fmt.Sprintf("%X", e.PrimaryKey.Fingerprint) - - for name, ident := range e.Identities { - // Pick first identity - if entity.Primary == nil { - entity.Primary, err = mail.ParseAddress(name) - if err != nil { - return entity, err - } - } - // If one is marked primary use that - if ident.SelfSignature != nil && ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { - entity.Primary, err = mail.ParseAddress(name) - if err != nil { - return entity, err - } - - } else { - var email *mail.Address - if email, err = mail.ParseAddress(name); err != nil { - return entity, err - } - if email.Address != entity.Primary.Address { - entity.Emails = append(entity.Emails, email) - } - } - - // If identity is self signed read notation data. - if ident.SelfSignature != nil && ident.SelfSignature.NotationData != nil { - entity.SelfSignature = ident.SelfSignature - // Get proofs and append to list. - if proofs, ok := ident.SelfSignature.NotationData["proof@metacode.biz"]; ok { - entity.Proofs = append(entity.Proofs, proofs...) - } - } - } - break - } - - if entity.Primary == nil { - entity.Primary, _ = mail.ParseAddress("nobody@nodomain.xyz") - } - - return entity, err -} - -func ReadKey(r io.Reader, useArmored bool) (e *Entity, err error) { +func ReadKey(r io.Reader, useArmored bool) (e *entity.Entity, err error) { var buf bytes.Buffer var w io.Writer = &buf - e = &Entity{} + e = &entity.Entity{} defer func() { if e != nil { @@ -187,7 +108,7 @@ func ReadKey(r io.Reader, useArmored bool) (e *Entity, err error) { return e, fmt.Errorf("Read key: %w", err) } - e, err = getEntity(lis) + e, err = entity.GetOne(lis) if err != nil { return e, fmt.Errorf("Parse key: %w", err) } diff --git a/pkg/keyproofs/style.go b/pkg/style/style.go similarity index 81% rename from pkg/keyproofs/style.go rename to pkg/style/style.go index 07f28c4..c3b396c 100644 --- a/pkg/keyproofs/style.go +++ b/pkg/style/style.go @@ -1,4 +1,4 @@ -package keyproofs +package style import ( "context" @@ -11,9 +11,11 @@ import ( "github.com/rs/zerolog/log" ) -type StyleKey string +var pixl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" -func (s StyleKey) Key() interface{} { +type Key string + +func (s Key) Key() interface{} { return s } @@ -25,10 +27,10 @@ type Style struct { Palette []string } -func getStyle(ctx context.Context, email string) (*Style, error) { +func GetStyle(ctx context.Context, email string) (*Style, error) { log := log.Ctx(ctx) - avatarHost, styleHost, err := styleSRV(ctx, email) + avatarHost, styleHost, err := GetSRV(ctx, email) if err != nil { return nil, err } @@ -41,10 +43,10 @@ func getStyle(ctx context.Context, email string) (*Style, error) { style := &Style{} - style.Palette = getPalette(fmt.Sprintf("#%x", id[:3])) + style.Palette = GetPalette(fmt.Sprintf("#%x", id[:3])) style.Avatar = fmt.Sprintf("https://%s/avatar/%x", avatarHost, id) style.Cover = pixl - style.Background = "https://lavana.sour.is/bg/52548b3dcb032882675afe1e4bcba0e9" + style.Background = pixl if styleHost != "" { style.Cover = fmt.Sprintf("https://%s/cover/%x", styleHost, id) @@ -54,11 +56,11 @@ func getStyle(ctx context.Context, email string) (*Style, error) { return style, err } -func styleSRV(ctx context.Context, email string) (avatar string, style string, err error) { +func GetSRV(ctx context.Context, email string) (avatar string, style string, err error) { // Defaults style = "" - avatar = "www.gravatar.com" + avatar = "www.libravatar.org" parts := strings.SplitN(email, "@", 2) if _, srv, err := net.DefaultResolver.LookupSRV(ctx, "style-sec", "tcp", parts[1]); err == nil { @@ -82,7 +84,7 @@ func styleSRV(ctx context.Context, email string) (avatar string, style string, e } // getPalette maes a complementary color palette. https://play.golang.org/p/nBXLUocGsU5 -func getPalette(hex string) []string { +func GetPalette(hex string) []string { reference, _ := colorful.Hex(hex) reference = sat(lum(reference, 0, .5), 0, .5)