diff --git a/go.mod b/go.mod index 56e0d5bbf0..729dad12f4 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,15 @@ module github.com/fleetdm/orbit go 1.15 require ( - github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 - github.com/docker/distribution v2.7.1+incompatible // indirect - github.com/kr/pretty v0.2.1 // indirect + github.com/dgraph-io/badger/v2 v2.2007.2 + github.com/golang/protobuf v1.3.4 // indirect + github.com/kr/text v0.2.0 // indirect github.com/oklog/run v1.1.0 github.com/pkg/errors v0.9.1 - github.com/sirupsen/logrus v1.7.0 // indirect + github.com/stretchr/objx v0.2.0 // indirect github.com/stretchr/testify v1.6.1 - github.com/theupdateframework/notary v0.6.2-0.20200804143915-84287fd8df4f + github.com/theupdateframework/go-tuf v0.0.0-20201230183259-aee6270feb55 github.com/urfave/cli/v2 v2.3.0 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect + golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e // indirect ) diff --git a/go.sum b/go.sum index 908d1221b1..ae24fb8f0a 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,16 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Shopify/logrus-bugsnag v0.0.0-20170309145241-6dbc35f2c30d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= -github.com/agl/ed25519 v0.0.0-20200225211852-fd4d107ace12 h1:iPf1jQ8yKTms6k6L5vYSE7RZJpjEe5vLTOmzRZdpnKc= -github.com/beorn7/perks v0.0.0-20150223135152-b965b613227f/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw= -github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= -github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= -github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= -github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= +github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -17,130 +18,110 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= -github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= -github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/go v1.5.1-1 h1:hr4w35acWBPhGBXlzPoHpmZ/ygPjnmFVxGxxGnMyP7k= -github.com/docker/go v1.5.1-1/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q= -github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0= -github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= -github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= -github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= +github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/flynn/go-docopt v0.0.0-20140912013429-f6dd2ebbb31e/go.mod h1:HyVoz1Mz5Co8TFO8EupIdlcpwShBmY98dkT2xeHkvEI= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= -github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +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/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= -github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= -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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 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= -github.com/prometheus/client_golang v0.9.0-pre1.0.20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +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/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= -github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v0.0.0-20150530192845-be5ff3e4840c/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= 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/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 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/theupdateframework/notary v0.6.1 h1:7wshjstgS9x9F5LuB1L5mBI2xNMObWqjz+cjWoom6l0= -github.com/theupdateframework/notary v0.6.1/go.mod h1:MOfgIfmox8s7/7fduvB2xyPPMJCrjRLRizA8OFwpnKY= -github.com/theupdateframework/notary v0.6.2-0.20200804143915-84287fd8df4f h1:myKguilK7Xy8V5sjfJ8CYn2cD/aRlDFO4hzkqZ9HhgQ= -github.com/theupdateframework/notary v0.6.2-0.20200804143915-84287fd8df4f/go.mod h1:VmySTua0RaZOe78Zx4/i3bCl9eNs0UvBOPV+1ps9t6U= -github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613 h1:iGnD/q9160NWqKZZ5vY4p0dMiYMRknzctfSkqA4nBDw= +github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613/go.mod h1:g6AnIpDSYMcphz193otpSIzN+11Rs+AAIIC6rm1enug= +github.com/theupdateframework/go-tuf v0.0.0-20201230183259-aee6270feb55 h1:Zn+mA4qTRyao2Petd+YovKaFOUuxDj158kqCIqvwTow= +github.com/theupdateframework/go-tuf v0.0.0-20201230183259-aee6270feb55/go.mod h1:L+uU/NRFK/7h0NYAnsmvsX9EghDB5QVCcHCIrK2h5nw= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20190424203555-c05e17bb3b2d/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -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-20181205085412-a5c9d58dba9a/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/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-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/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/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= -gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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/rethinkdb/rethinkdb-go.v6 v6.2.1/go.mod h1:WbjuEoo1oadwzQ4apSDU+JTvmllEHtsNHS6y7vFc7iw= 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.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/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= diff --git a/main.go b/main.go index ce6b91ed8d..8f9a926852 100644 --- a/main.go +++ b/main.go @@ -6,11 +6,14 @@ import ( "io/ioutil" "log" "os" + "path/filepath" "github.com/fleetdm/orbit/pkg/constant" + "github.com/fleetdm/orbit/pkg/database" "github.com/fleetdm/orbit/pkg/insecure" "github.com/fleetdm/orbit/pkg/osquery" "github.com/fleetdm/orbit/pkg/update" + "github.com/fleetdm/orbit/pkg/update/badgerstore" "github.com/oklog/run" "github.com/pkg/errors" "github.com/urfave/cli/v2" @@ -18,7 +21,7 @@ import ( const ( serverURL = "localhost:8080" - notaryURL = "https://localhost:4443" + notaryURL = "https://tuf.fleetctl.com" certPath = "/tmp/fleet.pem" ) @@ -26,7 +29,7 @@ func main() { app := cli.NewApp() app.Name = "Orbit osquery" app.Usage = "A powered-up, (near) drop-in replacement for osquery" - defaultRootDir := "/usr/local/orbit" + defaultRootDir := "/usr/local/fleet" app.Flags = []cli.Flag{ &cli.StringFlag{ Name: "root-dir", @@ -53,59 +56,37 @@ func main() { }, } app.Action = func(c *cli.Context) error { - // err := initialize(c) - // if err != nil { - // return errors.Wrap(err, "initialize") - // } + if err := os.MkdirAll(c.String("root-dir"), constant.DefaultDirMode); err != nil { + return errors.Wrap(err, "initialize root dir") + } - // rootDir := ".trust" - // if err := os.MkdirAll(rootDir, 0700); err != nil { - // panic(err) - // } - - // server := "https://localhost:4443" - // image := "example.com/collection" - // transport := http.DefaultTransport.(*http.Transport).Clone() - // transport.TLSClientConfig = &tls.Config{ - // InsecureSkipVerify: true, - // } - // repo, err := client.NewFileCachedRepository( - // rootDir, - // data.GUN(image), - // server, - // transport, - // nil, - // trustpinning.TrustPinConfig{}, - // ) - // if err != nil { - // panic(err) - // } - - // targets, err := repo.ListTargets() - // if err != nil { - // panic(err) - // } - - // for _, tgt := range targets { - // fmt.Printf("%s\t%s\n", tgt.Name, hex.EncodeToString(tgt.Hashes["sha256"])) - // } - - // tgt, err := repo.GetTargetByName("LICENSE") - // if err != nil { - // panic(err) - // } - // fmt.Printf("%+v\n", tgt) - - updater, err := update.New(update.Options{ - RootDirectory: c.String("root-dir"), - ServerURL: c.String("notary-url"), - InsecureTransport: true, - }) + db, err := database.Open(filepath.Join(c.String("root-dir"), "orbit.db")) + if err != nil { + return err + } + defer func() { + if err := db.Close(); err != nil { + log.Printf("Error closing badger: %v", err) + } + }() + + opt := update.DefaultOptions + opt.RootDirectory = c.String("root-dir") + opt.ServerURL = c.String("notary-url") + opt.LocalStore = badgerstore.New(db.DB) + updater, err := update.New(opt) + if err != nil { + return err + } + if err := updater.UpdateMetadata(); err != nil { + return err + } + log.Println(updater.Targets()) + + osquerydPath, err := updater.Get("osqueryd", "macos", "stable") if err != nil { return err } - fmt.Println(updater.Lookup("test", "LICENSE")) - _ = updater var g run.Group var options []func(*osquery.Runner) error @@ -146,9 +127,9 @@ func main() { ) } - if enrollSecret := c.String("enroll_secret"); enrollSecret != "" { + if enrollSecret := c.String("enroll-secret"); enrollSecret != "" { options = append(options, - osquery.WithEnv([]string{"ENROLL_SECRET="}), + osquery.WithEnv([]string{"ENROLL_SECRET=" + enrollSecret}), osquery.WithFlags([]string{"--enroll_secret_env", "ENROLL_SECRET"}), ) } @@ -163,6 +144,8 @@ func main() { osquery.WithFlags([]string{"--verbose"}), ) + options = append(options, osquery.WithPath(osquerydPath)) + // Create an osquery runner with the provided options r, _ := osquery.NewRunner(options...) g.Add(r.Execute, r.Interrupt) diff --git a/pkg/certificate/certificate_test.go b/pkg/certificate/certificate_test.go index 66fe400d74..13104a4e31 100644 --- a/pkg/certificate/certificate_test.go +++ b/pkg/certificate/certificate_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "github.com/bmizerany/assert" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/constant/constant.go b/pkg/constant/constant.go index 60060e3308..ce7ed7692b 100644 --- a/pkg/constant/constant.go +++ b/pkg/constant/constant.go @@ -5,4 +5,7 @@ const ( DefaultDirMode = 0o700 // DefaultFileMode is the default file mode to apply to created files. DefaultFileMode = 0o600 + // DefaultExecutableMode is the default file mode to apply to created + // executable files. + DefaultExecutableMode = 0o700 ) diff --git a/pkg/osquery/osquery.go b/pkg/osquery/osquery.go index 28e26150b5..f5a34bde98 100644 --- a/pkg/osquery/osquery.go +++ b/pkg/osquery/osquery.go @@ -59,13 +59,21 @@ func WithEnv(env []string) func(*Runner) error { } } +func WithPath(path string) func(*Runner) error { + return func(r *Runner) error { + r.cmd.Path = path + return nil + } +} + func (r *Runner) Execute() error { + ctx, cancel := context.WithCancel(context.Background()) + r.cancel = cancel + if err := r.proc.Start(); err != nil { return errors.Wrap(err, "start osquery") } - ctx, cancel := context.WithCancel(context.Background()) - r.cancel = cancel if err := r.proc.StopOrKill(ctx, 10*time.Second); err != nil { return errors.Wrap(err, "osquery exited with error") } diff --git a/pkg/update/badgerstore/badgerstore.go b/pkg/update/badgerstore/badgerstore.go new file mode 100644 index 0000000000..cbb97d94ea --- /dev/null +++ b/pkg/update/badgerstore/badgerstore.go @@ -0,0 +1,69 @@ +// package badgerstore implements the go-tuf LocalStore interface using Badger +// as a backing store. +package badgerstore + +import ( + "encoding/json" + "strings" + + "github.com/dgraph-io/badger/v2" + "github.com/theupdateframework/go-tuf/client" +) + +const ( + keyPrefix = ":tuf-metadata:" +) + +type badgerStore struct { + db *badger.DB +} + +// New creates the new store given the badger DB instance. +func New(db *badger.DB) client.LocalStore { + return &badgerStore{db: db} +} + +// SetMeta stores the provided metadata. +func (b *badgerStore) SetMeta(name string, meta json.RawMessage) error { + if err := b.db.Update(func(tx *badger.Txn) error { + if err := tx.Set([]byte(keyPrefix+name), meta); err != nil { + return err + } + return nil + }); err != nil { + return err + } + + return nil +} + +// GetMeta returns all of the saved metadata. +func (b *badgerStore) GetMeta() (map[string]json.RawMessage, error) { + res := make(map[string]json.RawMessage) + + // Iterate all keys with matching prefix + // Adapted from Badger docs + if err := b.db.View(func(txn *badger.Txn) error { + it := txn.NewIterator(badger.DefaultIteratorOptions) + defer it.Close() + prefix := []byte(keyPrefix) + for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() { + item := it.Item() + k := item.Key() + + if err := item.Value(func(v []byte) error { + // Remember to strip prefix + strippedKey := strings.TrimPrefix(string(k), keyPrefix) + res[strippedKey] = json.RawMessage(v) + return nil + }); err != nil { + return err + } + } + return nil + }); err != nil { + return res, err + } + + return res, nil +} diff --git a/pkg/update/badgerstore/badgerstore_test.go b/pkg/update/badgerstore/badgerstore_test.go new file mode 100644 index 0000000000..56fab9f72f --- /dev/null +++ b/pkg/update/badgerstore/badgerstore_test.go @@ -0,0 +1,31 @@ +package badgerstore + +import ( + "encoding/json" + "testing" + + "github.com/dgraph-io/badger/v2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestBadgerStore(t *testing.T) { + badgerClient, err := badger.Open(badger.DefaultOptions("").WithInMemory(true)) + require.NoError(t, err) + + store := New(badgerClient) + + expected := map[string]json.RawMessage{ + "test": json.RawMessage("json"), + "test2": json.RawMessage("json2"), + "root.json": json.RawMessage(`[{"keytype":"ed25519","scheme":"ed25519","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"0994148e5242118d1d6a9a397a3646e0423545a37794a791c28aa39de3b0c523"}}]`), + } + + for k, v := range expected { + require.NoError(t, store.SetMeta(k, v)) + } + + res, err := store.GetMeta() + require.NoError(t, err) + assert.Equal(t, expected, res) +} diff --git a/pkg/update/file.go b/pkg/update/file.go new file mode 100644 index 0000000000..696a55318e --- /dev/null +++ b/pkg/update/file.go @@ -0,0 +1,16 @@ +package update + +import "os" + +// fileDestination wraps the standard os.File with a Delete method for +// compatibility with the go-tuf Destination interface. +// Adapted from +// https://github.com/theupdateframework/go-tuf/blob/master/cmd/tuf-client/get.go +type fileDestination struct { + *os.File +} + +func (f *fileDestination) Delete() error { + _ = f.Close() + return os.Remove(f.Name()) +} diff --git a/pkg/update/hash.go b/pkg/update/hash.go new file mode 100644 index 0000000000..cd7fc69648 --- /dev/null +++ b/pkg/update/hash.go @@ -0,0 +1,52 @@ +package update + +import ( + "bytes" + "crypto/sha256" + "crypto/sha512" + "hash" + "io" + "os" + + "github.com/pkg/errors" + "github.com/theupdateframework/go-tuf/data" +) + +// CheckFileHash checks the file at the local path against the provided hash +// functions. +func CheckFileHash(meta *data.TargetFileMeta, localPath string) error { + hashFunc, hashVal, err := selectHashFunction(meta) + if err != nil { + return err + } + + f, err := os.Open(localPath) + if err != nil { + return errors.Wrap(err, "open file for hash") + } + + if _, err := io.Copy(hashFunc, f); err != nil { + return errors.Wrap(err, "read file for hash") + } + + if !bytes.Equal(hashVal, hashFunc.Sum(nil)) { + return errors.Errorf("hash %s does not match expected: %s", data.HexBytes(hashFunc.Sum(nil)), data.HexBytes(hashVal)) + } + + return nil +} + +// selectHashFunction returns the first matching hash function and expected +// hash, otherwise returning an error if not matching hash can be found. +func selectHashFunction(meta *data.TargetFileMeta) (hash.Hash, []byte, error) { + for hashName, hashVal := range meta.Hashes { + switch hashName { + case "sha512": + return sha512.New(), hashVal, nil + case "sha256": + return sha256.New(), hashVal, nil + } + } + + return nil, nil, errors.Errorf("no matching hash function found: %v", meta.HashAlgorithms()) +} diff --git a/pkg/update/update.go b/pkg/update/update.go index 0513ff624e..979a91b767 100644 --- a/pkg/update/update.go +++ b/pkg/update/update.go @@ -2,20 +2,19 @@ package update import ( - "bytes" - "crypto/sha512" "crypto/tls" - "encoding/base64" - "io" + "encoding/json" + "io/ioutil" + "log" "net/http" "os" + "path" "path/filepath" "github.com/fleetdm/orbit/pkg/constant" "github.com/pkg/errors" - "github.com/theupdateframework/notary/client" - "github.com/theupdateframework/notary/trustpinning" - "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/go-tuf/client" + "github.com/theupdateframework/go-tuf/data" ) const ( @@ -23,13 +22,14 @@ const ( osqueryDir = "osquery" orbitDir = "orbit" - notaryDir = "notary" + windowsExtension = ".exe" ) // Updater is responsible for managing update state. type Updater struct { opt Options transport *http.Transport + client *client.Client } // Options are the options that can be provided when creating an Updater. @@ -38,13 +38,27 @@ type Options struct { RootDirectory string // ServerURL is the URL of the update server. ServerURL string - // GUN is the Globally Unique Name to look up with the Notary server. - GUN string // InsecureTransport skips TLS certificate verification in the transport if // set to true. InsecureTransport bool + // RootKeys is the JSON encoded root keys to use to bootstrap trust. + RootKeys string + // LocalStore is the local metadata store. + LocalStore client.LocalStore } +var ( + // DefaultOptions are the default options to use when creating an update + // client. + DefaultOptions = Options{ + RootDirectory: "/var/fleet", + ServerURL: "https://tuf.fleetctl.com", + LocalStore: client.MemoryLocalStore(), + InsecureTransport: false, + RootKeys: `[{"keytype":"ed25519","scheme":"ed25519","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"0994148e5242118d1d6a9a397a3646e0423545a37794a791c28aa39de3b0c523"}}]`, + } +) + // New creates a new updater given the provided options. All the necessary // directories are initialized. func New(opt Options) (*Updater, error) { @@ -52,40 +66,136 @@ func New(opt Options) (*Updater, error) { transport.TLSClientConfig = &tls.Config{ InsecureSkipVerify: opt.InsecureTransport, } + httpClient := &http.Client{Transport: transport} - updater := &Updater{ - opt: opt, - transport: transport, + remoteStore, err := client.HTTPRemoteStore(opt.ServerURL, nil, httpClient) + if err != nil { + return nil, errors.Wrap(err, "init remote store") } - err := updater.initializeDirectories() - if err != nil { + tufClient := client.NewClient(opt.LocalStore, remoteStore) + var rootKeys []*data.Key + if err := json.Unmarshal([]byte(opt.RootKeys), &rootKeys); err != nil { + return nil, errors.Wrap(err, "unmarshal root keys") + } + if err := tufClient.Init(rootKeys, 1); err != nil { + return nil, errors.Wrap(err, "init tuf client") + } + + updater := &Updater{ + opt: opt, + client: tufClient, + } + + if err := updater.initializeDirectories(); err != nil { return nil, err } return updater, nil } -// Lookup returns the target metadata for the provided GUN and target name. -func (u *Updater) Lookup(GUN, target string) (*client.Target, error) { - client, err := client.NewFileCachedRepository( - u.pathFromRoot(notaryDir), - data.GUN(GUN), - u.opt.ServerURL, - u.transport, - nil, - trustpinning.TrustPinConfig{}, - ) +func (u *Updater) UpdateMetadata() error { + if _, err := u.client.Update(); err != nil && errors.Is(err, &client.ErrLatestSnapshot{}) { + return errors.Wrap(err, "update metadata") + } + return nil +} + +func makeRepoPath(name, platform, version string) string { + path := path.Join(name, platform, version, name) + if platform == "windows" { + path += windowsExtension + } + return path +} + +func makeLocalPath(name, platform, version string) string { + path := filepath.Join(name, version, name) + if platform == "windows" { + path += windowsExtension + } + return path +} + +// Lookup looks up the provided target in the local target metadata. This should +// be called after UpdateMetadata. +func (u *Updater) Lookup(name, platform, version string) (*data.TargetFileMeta, error) { + target, err := u.client.Target(makeRepoPath(name, platform, version)) if err != nil { - return nil, errors.Wrap(err, "make notary client") + return nil, errors.Wrapf(err, "lookup target %s", target) } - targetWithRole, err := client.GetTargetByName(target) + return &target, nil +} + +// Targets gets all of the known targets +func (u *Updater) Targets() (data.TargetFiles, error) { + targets, err := u.client.Targets() if err != nil { - return nil, errors.Wrap(err, "get target by name") + return nil, errors.Wrapf(err, "get targets") } - return &targetWithRole.Target, nil + return targets, nil +} + +// Get returns the local path to the specified target. The target is downloaded +// if it does not yet exist locally or the hash does not match. +func (u *Updater) Get(name, platform, version string) (string, error) { + localPath := u.pathFromRoot(makeLocalPath(name, platform, version)) + repoPath := makeRepoPath(name, platform, version) + stat, err := os.Stat(localPath) + if err != nil { + log.Println("error stat file:", err) + return localPath, u.Download(repoPath, localPath) + } + if !stat.Mode().IsRegular() { + return "", errors.Errorf("expected %s to be regular file", localPath) + } + + meta, err := u.Lookup(name, platform, version) + if err != nil { + return "", err + } + + if err := CheckFileHash(meta, localPath); err != nil { + log.Printf("Will redownload due to error checking hash: %v", err) + return localPath, u.Download(repoPath, localPath) + } + + log.Printf("Found expected version locally: %s", localPath) + + return localPath, nil +} + +// Download downloads the target to the provided path. The file is deleted and +// an error is returned if the hash does not match. +func (u *Updater) Download(repoPath, localPath string) error { + tmp, err := ioutil.TempFile("", "orbit-download") + if err != nil { + return errors.Wrap(err, "open temp file for download") + } + defer func() { + tmp.Close() + os.Remove(tmp.Name()) + }() + + if err := os.MkdirAll(filepath.Dir(localPath), constant.DefaultDirMode); err != nil { + return errors.Wrap(err, "initialize download dir") + } + + if err := u.client.Download(repoPath, &fileDestination{tmp}); err != nil { + return errors.Wrapf(err, "download target %s", repoPath) + } + + if err := os.Chmod(tmp.Name(), constant.DefaultExecutableMode); err != nil { + return errors.Wrap(err, "chmod download") + } + + if err := os.Rename(tmp.Name(), localPath); err != nil { + return errors.Wrap(err, "move download") + } + + return nil } func (u *Updater) pathFromRoot(parts ...string) string { @@ -97,7 +207,6 @@ func (u *Updater) initializeDirectories() error { u.pathFromRoot(binDir), u.pathFromRoot(binDir, osqueryDir), u.pathFromRoot(binDir, orbitDir), - u.pathFromRoot(notaryDir), } { err := os.MkdirAll(dir, constant.DefaultDirMode) if err != nil { @@ -107,54 +216,3 @@ func (u *Updater) initializeDirectories() error { return nil } - -// DownloadWithSHA512Hash downloads the contents of the given URL, writing -// results to the provided writer. The size is used as an upper limit on the -// amount of data read. An error is returned if the hash of the data received -// does not match the expected hash. -func DownloadWithSHA512Hash(url string, out io.Writer, size int64, expectedHash []byte) error { - resp, err := http.Get(url) - if err != nil { - return errors.Wrap(err, "make get request") - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return errors.Errorf("unexpected HTTP status: %s", resp.Status) - } - - hash := sha512.New() - - // Limit size of response read to expected size - limitReader := &io.LimitedReader{ - R: resp.Body, - N: size + 1, - } - - // Tee the bytes through the hash function - teeReader := io.TeeReader(limitReader, hash) - - n, err := io.Copy(out, teeReader) - if err != nil { - return errors.Wrap(err, "copy response body") - } - // Technically these cases would be caught by the hash, but these errors are - // hopefully a bit more helpful. - if n < size { - return errors.New("response smaller than expected") - } - if n > size { - return errors.New("response larger than expected") - } - - // Validate the hash matches - gotHash := hash.Sum(nil) - if !bytes.Equal(gotHash, expectedHash) { - return errors.Errorf( - "hash %s does not match expected %s", - base64.StdEncoding.EncodeToString(gotHash), - base64.StdEncoding.EncodeToString(expectedHash), - ) - } - - return nil -} diff --git a/pkg/update/update_test.go b/pkg/update/update_test.go index c7f8175bda..84f148480d 100644 --- a/pkg/update/update_test.go +++ b/pkg/update/update_test.go @@ -1,12 +1,7 @@ package update import ( - "bytes" - "crypto/sha512" - "fmt" "io/ioutil" - "net/http" - "net/http/httptest" "os" "path/filepath" "testing" @@ -15,103 +10,6 @@ import ( "github.com/stretchr/testify/require" ) -func TestDownloadWithSHA512HashInvalidURL(t *testing.T) { - t.Parallel() - - err := DownloadWithSHA512Hash("localhost:12345569900", ioutil.Discard, 55, nil) - require.Error(t, err) - assert.Contains(t, err.Error(), "make get request") -} - -func TestDownloadWithSHA512HashErrorResponse(t *testing.T) { - t.Parallel() - - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - http.Error(w, "error", http.StatusInternalServerError) - })) - defer ts.Close() - - err := DownloadWithSHA512Hash(ts.URL, ioutil.Discard, 55, nil) - require.Error(t, err) - assert.Contains(t, err.Error(), "unexpected HTTP status") -} - -func TestDownloadWithSHA512Hash(t *testing.T) { - t.Parallel() - - expectedData := []byte("abc") - expectedHash, expectedLen := sha512Hash(expectedData), int64(len(expectedData)) - - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, string(expectedData)) - })) - defer ts.Close() - - var b bytes.Buffer - err := DownloadWithSHA512Hash(ts.URL, &b, expectedLen, expectedHash) - require.NoError(t, err) - assert.Equal(t, expectedData, b.Bytes()) -} - -func TestDownloadWithSHA512HashTooSmall(t *testing.T) { - t.Parallel() - - expectedData := []byte("abc") - expectedHash, expectedLen := sha512Hash(expectedData), int64(len(expectedData)) - - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Don't write all of data - fmt.Fprint(w, string(expectedData[:2])) - })) - defer ts.Close() - - err := DownloadWithSHA512Hash(ts.URL, ioutil.Discard, expectedLen, expectedHash) - require.Error(t, err) - assert.Contains(t, err.Error(), "small") -} - -func TestDownloadWithSHA512HashTooLarge(t *testing.T) { - t.Parallel() - - expectedData := []byte("abc") - expectedHash, expectedLen := sha512Hash(expectedData), int64(len(expectedData)) - - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Write additional data - fmt.Fprintf(w, string(expectedData)+"foobar") - })) - defer ts.Close() - - err := DownloadWithSHA512Hash(ts.URL, ioutil.Discard, expectedLen, expectedHash) - require.Error(t, err) - assert.Contains(t, err.Error(), "large") -} - -func TestDownloadWithSHA512HashMismatch(t *testing.T) { - t.Parallel() - - expectedData := []byte("abc") - expectedHash, expectedLen := sha512Hash(expectedData), int64(len(expectedData)) - - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Write non-matching data - fmt.Fprint(w, string("def")) - })) - defer ts.Close() - - err := DownloadWithSHA512Hash(ts.URL, ioutil.Discard, expectedLen, expectedHash) - require.Error(t, err) - assert.Contains(t, err.Error(), "not match") -} - -func sha512Hash(data []byte) []byte { - hash := sha512.New() - if _, err := hash.Write(data); err != nil { - panic(err) - } - return hash.Sum(nil) -} - func TestInitializeDirectories(t *testing.T) { t.Parallel() @@ -119,12 +17,14 @@ func TestInitializeDirectories(t *testing.T) { require.NoError(t, err) defer os.RemoveAll(tmpDir) - _, err = New(Options{RootDirectory: tmpDir}) + opt := DefaultOptions + opt.RootDirectory = tmpDir + updater := Updater{opt: opt} + err = updater.initializeDirectories() require.NoError(t, err) assertDir(t, filepath.Join(tmpDir, binDir)) assertDir(t, filepath.Join(tmpDir, binDir, osqueryDir)) assertDir(t, filepath.Join(tmpDir, binDir, orbitDir)) - assertDir(t, filepath.Join(tmpDir, notaryDir)) } func assertDir(t *testing.T, path string) { @@ -132,3 +32,25 @@ func assertDir(t *testing.T, path string) { assert.NoError(t, err, "stat should succeed") assert.True(t, info.IsDir()) } + +func TestMakePath(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + platform string + version string + expected string + }{ + {name: "osqueryd", platform: "linux", version: "4.6.0", expected: "osqueryd/linux/4.6.0/osqueryd"}, + {name: "osqueryd", platform: "windows", version: "3.3.2", expected: "osqueryd/windows/3.3.2/osqueryd.exe"}, + } + + for _, tt := range testCases { + t.Run(tt.expected, func(t *testing.T) { + t.Parallel() + + assert.Equal(t, tt.expected, makePath(tt.name, tt.platform, tt.version)) + }) + } +}