├── .circleci └── config.yml ├── .gitignore ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── README.md ├── VERSION ├── contract.go ├── contract ├── killcord.abi ├── killcord.bin ├── killcord.go └── killcord.sol ├── contract_test.go ├── docker-compose.yml ├── examples └── lambda │ └── main.go ├── go.mod ├── go.sum ├── images ├── logo.png └── relational-diagram.png ├── killcord ├── cmd │ ├── checkin.go │ ├── contract.go │ ├── decrypt.go │ ├── encrypt.go │ ├── init.go │ ├── payload.go │ ├── publish.go │ ├── publisher.go │ ├── root.go │ ├── status.go │ ├── version.go │ └── watch.go └── main.go ├── payload.go ├── payload_test.go ├── project.go ├── project_test.go ├── publisher.go ├── publisher_test.go ├── scripts ├── build-release.sh ├── build.sh └── contract-gen.sh ├── status.go └── status_test.go /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Golang CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-go/ for more details 4 | version: 2 5 | jobs: 6 | build: 7 | docker: 8 | - image: cimg/go:1.18 9 | steps: 10 | - checkout 11 | # specify any bash command here prefixed with `run: ` 12 | - run: go test -v ./... 13 | - run: go test -race -coverprofile=coverage.txt -covermode=atomic 14 | # send code coverage to codecov 15 | - run: bash <(curl -s https://codecov.io/bash) 16 | workflows: 17 | version: 2 18 | build: 19 | jobs: 20 | - build: 21 | context: org-global -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | coverage.txt 13 | 14 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 15 | .glide/ 16 | 17 | 18 | .DS_Store -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.0.1-alpha] - 2018-02-26 10 | ### Added 11 | - initial commits of killcord 12 | - added (this) CHANGELOG -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.15.5 2 | WORKDIR /go/src/github.com/nomasters/killcord 3 | RUN apt-get update && apt-get upgrade -y && apt-get install python python-pip zip unzip -y 4 | RUN pip install awscli 5 | COPY . . -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ARCHIVED PROJECT, NO FUTURE UPDATES 2 | I appreciate you checking out my old project. A few years ago I was interested in exploring claims made by IPFS and ETH, and this was a toy project I built to experiment with that. I do not plan to update or maintain this project, and I'm leaving it up for historical reasons. Feel free to learn from this repo, but I will not be maintaining this or updating this anylong and I'll be marking it as ARCHIVE. 3 | 4 | 5 | 6 | # Original project README below 7 | 8 | 9 | 10 | 11 | 12 | ![killcord logo](images/logo.png) 13 | 14 | # killcord 15 | 16 | ## v0.0.1 17 | 18 | [![circleci][1]][2] [![Go Report Card][3]][4] 19 | 20 | [1]: https://circleci.com/gh/nomasters/killcord.svg?style=shield&circle-token=46ac657a268fef44dc132ef2241291c51811edd2 21 | [2]: https://circleci.com/gh/nomasters/killcord 22 | [3]: https://goreportcard.com/badge/github.com/nomasters/killcord?cache=false 23 | [4]: https://goreportcard.com/report/github.com/nomasters/killcord 24 | 25 | **WARNING** This software is in early _alpha_. Please do not rely on this with your life. Though great care has been taken to ensure that this code is as well structured and straight-forward as possible, it has not undergone proper peer-review and could have both minor and major bugs that undermine the integrity of the system. 26 | 27 | 28 | ## Summary 29 | 30 | `killcord` is an early prototype of a censorship resistant [dead man's switch](https://en.wikipedia.org/wiki/Dead_man%27s_switch) for revealing the cryptographic key to a publicly accessible encrypted payload. 31 | 32 | ![killcord relational diagram](images/relational-diagram.png) 33 | 34 | `killcord` leverages: 35 | 36 | - [ipfs](https://ipfs.io/) for decentralized, immutable, peer-to-peer storage of the encrypted payload 37 | - [an ethereum smart contract](https://solidity.readthedocs.io/en/develop/introduction-to-smart-contracts.html) for trustless and censorship resistant application state. 38 | - a hidden `publisher` written in `go` that communicates with the `ethereum` smart contract and publishes the `ipfs` stored encrypted payload key in the event that the `killcord` owner stops checking in. 39 | - a client `killcord cli` written in `go` meant to run on a personally controlled system that bootstraps the entire `killcord` system and allows for checkins. 40 | 41 | ### killcord overview 42 | 43 | `killcord` is designed for a project owner to be able to automatically release a decryption key in the circumstance that the owner stops _checking-in_ after a predefined window of time. This allows an owner to release a secret data dump to the public in the event of death or disappearance. 44 | 45 | - It leverages `ipfs` for its censorship resistance and the ability to cheaply and efficiently hold and share data sets of an arbitrary size. 46 | 47 | - It leverages **ethereum smart contracts** as the backbone to the `checkin` and `publish` system. The killcord smart contract holds the **source of truth** for the ipfs `storageEndpoint` hash, the `lastCheckIn` data, and the `publishedKey`, in the event that the secret key is published. 48 | 49 | - It leverages a `publisher` tool meant to run autonomously on a trusted system or set of systems. In its current form, it runs under a special `publisher` identity. The publisher watches the smart contract for the `LastCheckin` state and follows a set of publication rules. For example, if the `publisher` is configured to publish in the event that the `LastCheckIn` was greater than 48 hours from the current time, the `publisher` would attempt to publish the `decryptionKey` for the IPFS payload to the smart contract. The `publisher` is portable enough to run on a raspberry pi and even has an [aws lambda](https://aws.amazon.com/lambda/) handler so that it can be scheduled on lambda for virtually no cost. 50 | 51 | ### killcord client (CLI) 52 | 53 | To install killcord, you can download precompiled binaries from latest release from the releases tab on github. Once downloaded, move `killcord` to your path, such as `/usr/local/bin/`. 54 | 55 | 56 | If you have `go` installed, you can install the killcord cli tool by running: 57 | 58 | ``` 59 | go install github.com/nomasters/killcord/killcord 60 | ``` 61 | 62 | 63 | `killcord` is a command-line tool meant to run from a personally trusted system. It is the primary interface to either `own` or `watch` a `killcord project`. 64 | 65 | 66 | ***killcord projects*** allow an `owner` to upload an encrypted payload to IPFS with a globally unique `hash` that is tied to a smart contract on ethereum. `killcord` creates unique `ipfs` and `ethereum` accounts for each project (one for the contract owner and one for the publisher), and once a small amount of `ETH` has been added to the newly generated account, it deploys a smart contract closely tied to the `owner` of the account. Only the account owner is allowed to make writes to all functions on the smart contract, the publisher is only allowed to make writes on the `publishedKey` function. 67 | 68 | The owner can interact with the project, once deployed with: 69 | 70 | - **checkin** - a command used to let `killcord` know the owner is still around 71 | - **status** - a command used to check the status of the existing contract 72 | - **publish** - the command used to bypass the `publisher` and post the decryption key to the smart contract. 73 | 74 | 75 | #### Running killcord as an owner 76 | 77 | With `killcord`, the project owner has a special status. A project owner controls the initialization, deployment, and updating steps involved in a `killcord project`. 78 | 79 | Killcord projects have all of the configurations contained within the project directory. This includes all account information, secrets, and environmental variables related to the `killcord project`. This allows you to run multiple killcord projects as an owner or a watcher as you see fit. 80 | 81 | To create a new `killcord project` as an owner, create an empty directory for the project. 82 | 83 | ``` 84 | $ mkdir my-example-killcord 85 | $ cd my-example-killcord 86 | 87 | ``` 88 | then you will want to initialize the project that defaults to the `ropsten` testnet on ethereum. 89 | ``` 90 | $ killcord init --dev 91 | ``` 92 | 93 | This will setup a `killcord.toml` configuration file that includes 2 new ethereum accounts. The first account is your `owner` account. This is the account that owns the contract on ethereum and it is tied to the owner project on your personal system. The second account is for your publisher. This is a special account with lower privileges that is only allowed to publish your key to the contract. 94 | 95 | Once created, you will be given instructions on the owner and publisher accounts addresses that needs ETH to move forward. You should fund this account with ETH before moving forward. 96 | 97 | Since we are running this project on the `testnet` you can get free ETH to test by installing [metamask](https://metamask.io/) and requesting some ETH from the [MetaMask Ether Faucet](https://faucet.metamask.io/). 98 | 99 | NOTE: 1 ETH is more than enough to experiment with `killcord` 100 | 101 | Before you continue, check your killcord account balances with the `status` command 102 | 103 | ``` 104 | $ killcord status 105 | ``` 106 | 107 | Once your owner account is funded, you should deploy your contract: 108 | 109 | ``` 110 | $ killcord contract deploy 111 | ``` 112 | 113 | This will deploy the smart contract for your killcord project in an incomplete state. A contract needs to be linked to an ipfs encrypted payload before it is ready to be monitored by the publisher. 114 | 115 | 116 | #### preparing your payload 117 | 118 | The encrypted data payload for killcord utilizes [NaCL secretbox](https://nacl.cr.yp.to/secretbox.html) to encrypt a single-file payload. This file uses a 256 bit key that is randomly generated and saved inside of the project to be utilized by either the owner or publisher. 119 | 120 | Place your files in the `payload/source` folder in your project. If `killcord` recognizes multiple files in this directory, it will automatically zip these files for you before encrypting it. 121 | 122 | ``` 123 | $ killcord encrypt 124 | ``` 125 | 126 | This command encrypts your data, saves it into the `payload/encrypted` directory and saves the encryption key to the `killcord.toml` file. 127 | 128 | to test that the payload will decrypt properly, use: 129 | 130 | ``` 131 | $ killcord decrypt 132 | ``` 133 | 134 | This will decrypt a payload found in the `payload-encrypted` directory and save it to the `payload-decrypted` directory. This should match the contents of the `payload-source` directory. 135 | 136 | Now that we have an encrypted payload, we need to deploy it to `ipfs`. run: 137 | 138 | ``` 139 | $ killcord payload deploy 140 | ``` 141 | 142 | This adds the encrypted payload to `ipfs`, it writes the `ipfs` hash to you project configuration. Then, it updates your smart contract so that it is able to reference the IPFS hash as well. 143 | 144 | #### an important consideration about deploying your payload to IPFS 145 | 146 | `ipfs` is a decentralized permanent web. This means that anything posted there has a high likelihood of sticking around permanently. Existentially this means that killcord payloads should be treated very carefully. Payloads that exist should be intended for the public. This can't be overstated. 147 | 148 | Reasons that a payload could be decrypted before you intend it to be: 149 | 150 | - there is a flaw in `secretbox` that exposes a vulnerability in the encryption 151 | - there is a flaw in the killcord implementation of `secretbox` that exposes a vulnerability in the encryption 152 | - the owner's secret is divulged due to a compromised computer system 153 | - the owner fails to properly fund the owner ethereum account causing the publisher to publish the key 154 | - the owner fails to checkin due to neglect causing the publisher to publish the key 155 | 156 | The safest way to think about posting any encrypted payload to IPFS is that it _will_ one day be decrypted. If you are not comfortable with your payload eventually being public, you should not use this tool. 157 | 158 | ### checking in 159 | 160 | You now have a fully configured `owner` account. We still need to configure a `publisher` that will publish on your behalf in the event that you stop checking in, but first, let's checkin before moving forward: 161 | 162 | ``` 163 | killcord checkin 164 | ``` 165 | 166 | This is the primary action the `owner` will take from this point forward. A checkin engages the smart contract with the owner account. Under the hood, the smart contract grabs the `block.timestamp` of the block this transaction is part of and writes that timestamp to the `lastCheckIn` variable. It is important to note that ethereum allows a timestamp drift of up to 900 seconds (15 minutes) by the miner, so it is important to keep this in mind when creating your Publisher, any timestamp can be +/- 15 minutes from reality. By default `killcord` uses a publish threshold of 48 hours. 167 | 168 | ### check status 169 | 170 | You can get your `lastCheckin` recorded to the block chain at any time by running: 171 | 172 | ``` 173 | killcord status 174 | ``` 175 | 176 | ### killing a contract 177 | 178 | ``` 179 | killcord contract --kill 180 | ``` 181 | 182 | This kills the contract. Once a contract is killed, it cannot be undone, the owner would have to start a new project to continue. 183 | 184 | #### an important consideration about killing contracts 185 | 186 | It is important to note that though the contract and its variables will no longer be available, analysis tools for the blockchain that can extract variable state. Killing a contract will stop the contract from mutating in the future, but it will not delete old data. Data posted to your killcord contract is permanently stored on the ethereum blockchain. 187 | 188 | ### publish (owner override) 189 | 190 | 191 | ``` 192 | killcord publish 193 | ``` 194 | 195 | This bypasses the automated publisher and publishes the decryption key for the contract. 196 | 197 | 198 | ### configuring a watcher 199 | 200 | A watcher is a non-privileged killcord project that downloads a local copy of the encrypted payload and watches the contract for the publication of a secret. 201 | 202 | To start a watcher project create a new directory for the project 203 | 204 | ``` 205 | $ mkdir my-example-killcord-watcher 206 | $ cd my-example-killcord-watcher 207 | 208 | ``` 209 | 210 | Initialize the watcher, since our example above used the `testnet` we'll use the testnet here as well. 211 | 212 | ``` 213 | $ killcord watch 0x1dc634148b6d6537e95c26ddaabfc19e0f30e876 --dev 214 | ``` 215 | 216 | if the payload secret is already written to the contract, killcord will write the secret to the config on project creation, simply run 217 | 218 | ``` 219 | killcord decrypt 220 | ``` 221 | 222 | to see the payload. 223 | 224 | If the project has not yet published its key, simply run 225 | 226 | ``` 227 | killcord status 228 | ``` 229 | 230 | this will give the watcher an update of the contract status, if the key is published, `status` will write the payload secret to the configuration file and notify the watcher that the secret was published. 231 | 232 | ### configuring the publisher 233 | 234 | Currently, this is the least mature part of killcord and requires a bit of manual configuration. This is slated to change over the next few releases, but this section will outline what it will take to get a publisher running. 235 | 236 | The publisher requires a subset of values from the `killcord.toml` to work. 237 | 238 | ```toml 239 | devMode = true # optional, defaults to false 240 | 241 | [payload] 242 | secret = "SECRET" 243 | rpcUrl = "" # optional, defaults to infura 244 | 245 | [contract] 246 | id = "CONTRACT" 247 | mode = "testnet" # optional, defaults to mainnet 248 | rpcUrl = "" # optional, defaults to infura 249 | [contract.publisher] 250 | address = "HASH" 251 | password = "PASSWORD" 252 | keystore = "KEYSTORE" 253 | [publisher] 254 | warningThreshold = 0 # optional, defaults to 24 hours 255 | publishThreshold = 0 # optional, defaults to 48 hours 256 | ``` 257 | 258 | 259 | These settings can also be expressed as environmental variables. 260 | 261 | Required fields are: 262 | 263 | ``` 264 | KILLCORD_PAYLOAD_SECRET 265 | KILLCORD_CONTRACT_ID 266 | KILLCORD_CONTRACT_PUBLISHER_ADDRESS 267 | KILLCORD_CONTRACT_PUBLISHER_PASSWORD 268 | KILLCORD_CONTRACT_PUBLISHER_KEYSTORE 269 | ``` 270 | 271 | Optional fields are: 272 | 273 | ``` 274 | KILLCORD_DEV_MODE \\ defaults to false 275 | KILLCORD_PUBLISHER_WARNING_THRESHOLD \\ defaults to 24 hours if not included 276 | KILLCORD_PUBLISHER_PUBLISH_THRESHOLD \\ defaults to 48 hours if not included 277 | KILLCORD_PAYLOAD_RPCURL \\ defaults to infura.io 278 | KILLCORD_CONTRACT_RPCURL \\ defaults to infura.io 279 | ``` 280 | 281 | To run the publisher one time from inside of the owner project, you can simply run 282 | 283 | ``` 284 | killcord publisher run 285 | ``` 286 | 287 | this runs the publisher and defaults to returning a warning if it has been 24 hours since the last checkin and defaults to publishing the payload secret after 48 hours from the last checkin. 288 | 289 | You can manually change these thresholds in the `killcord.toml` file or by setting the ENV_VARs outlined above. 290 | 291 | ### scheduling the publisher 292 | 293 | Once a publisher is configured, the next step will be to schedule its runs. Currently there is no automatic way of doing this, but there are several solutions in the works including easy deploy tools for `docker` and `aws lambda`, and they are actively being worked on. 294 | 295 | Without any special setups, `killcord publisher run` can be scheduled with common unix tools such as `cron`. 296 | 297 | Killcord also provides an ***aws lambda*** handler, and an example project leveraging [apex.run](http://apex.run/) is in the `examples/` directory in this repo 298 | 299 | ### Connecting your own ETH and IPFS nodes to killcord 300 | 301 | By default `killcord` uses [infura](https://infura.io/) to make connections to ethereum and IPFS effortless, but if you are a more advanced user, you are encouraged to participate in hosting your own decentralized nodes. 302 | 303 | There are two ways to wire up custom RPC endpoints 304 | 305 | - add the RPC endpoint to the `killcord.toml` config file 306 | - configure environmental variables for `KILLCORD_CONTRACT_RPCURL` and `KILLCORD_PAYLOAD_RPCURL` 307 | 308 | ## getting involved 309 | 310 | If you find this project interesting, I'd love your help. you can reach [me on keybase](https://keybase.io/rjrbt) or even better, join the [killcord group chat on keybase](https://keybase.io/team/killcord). 311 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.0.1-alpha -------------------------------------------------------------------------------- /contract.go: -------------------------------------------------------------------------------- 1 | package killcord 2 | 3 | import ( 4 | "context" 5 | "encoding/hex" 6 | "errors" 7 | "fmt" 8 | "io/ioutil" 9 | "log" 10 | "math/big" 11 | "os" 12 | "path/filepath" 13 | "strings" 14 | "time" 15 | 16 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 17 | "github.com/ethereum/go-ethereum/accounts/keystore" 18 | "github.com/ethereum/go-ethereum/common" 19 | "github.com/ethereum/go-ethereum/ethclient" 20 | "github.com/nomasters/killcord/contract" 21 | ) 22 | 23 | const ( 24 | defaultETHRPCPDev = "https://ropsten.infura.io/v3/31eba034ccd74fc8ab6ac9ba0e24da2f" 25 | defaultETHRPCDProd = "https://mainnet.infura.io/v3/31eba034ccd74fc8ab6ac9ba0e24da2f" 26 | ) 27 | 28 | var ( 29 | contractDir string 30 | fullKeyStorePath string 31 | relativeKeyStorePath string 32 | ethereumRPCPath string = defaultETHRPCPDev 33 | ) 34 | 35 | func init() { 36 | contractDir = filepath.Join(ProjectPath, "contract") 37 | fullKeyStorePath = filepath.Join(contractDir, "data", "keystore") 38 | relativeKeyStorePath = filepath.Join("contract", "data", "keystore") 39 | } 40 | 41 | // A simple func to convert wei to ETH 42 | func weiToETH(i *big.Int) float64 { 43 | f := float64(i.Int64()) 44 | return f / 1000000000000000000 45 | } 46 | 47 | // Gracefully resolve Ethereum RPC path by waterfalling through 48 | // Options > Project > Defaults 49 | func (s *Session) setEthereumRPCPath() { 50 | if s.Options.Contract.RPCURL != "" { 51 | ethereumRPCPath = s.Options.Contract.RPCURL 52 | return 53 | } 54 | if s.Config.Contract.RPCURL != "" { 55 | ethereumRPCPath = s.Config.Contract.RPCURL 56 | return 57 | } 58 | if s.Config.Contract.Mode == "mainnet" { 59 | ethereumRPCPath = defaultETHRPCDProd 60 | return 61 | } 62 | s.Config.Contract.Mode = "testnet" 63 | ethereumRPCPath = defaultETHRPCPDev 64 | } 65 | 66 | // ConfigEthereum configures the ethereum accounts used by killcord and adds 67 | // the settings to the primary config. This includes account 68 | // generation, password creation, and keystore creation. 69 | func (s *Session) ConfigEthereum() error { 70 | ks := newKeyStore() 71 | if err := s.Config.Contract.Owner.New(ks); err != nil { 72 | return err 73 | } 74 | if err := s.Config.Contract.Publisher.New(ks); err != nil { 75 | return err 76 | } 77 | fmt.Println("ethereum: initializing") 78 | s.Config.Contract.Provider = "ethereum" 79 | s.Config.Contract.Status = "initialized" 80 | fmt.Println("ethereum: configured") 81 | 82 | fmt.Printf(` 83 | 84 | Congrats! You've successfully initialized your ethereum owner and publisher accounts. 85 | Next, you'll need to add a little bit of ETH to both accounts to move forward. 86 | 87 | You should add a minimum of: 88 | 89 | - 0.03 ETH to your owner account 90 | - 0.01 ETH to your publisher account 91 | 92 | your owner account address is: 0x%v 93 | your publisher account address is: 0x%v 94 | 95 | You can check your ethereum account balances with the "killcord status" command. 96 | If this is your first time using Ethereum, metamask (https://metamask.io/) is the 97 | easiest way to get started. 98 | 99 | `, s.Config.Contract.Owner.Address, s.Config.Contract.Publisher.Address) 100 | 101 | return nil 102 | } 103 | 104 | func newKeyStore() *keystore.KeyStore { 105 | return keystore.NewKeyStore(fullKeyStorePath, keystore.StandardScryptN, keystore.StandardScryptP) 106 | } 107 | 108 | // New makes a account 109 | func (a *AccountConfig) New(ks *keystore.KeyStore) error { 110 | pw := generateKey() 111 | newAcc, err := ks.NewAccount(pw) 112 | if err != nil { 113 | return err 114 | } 115 | a.Address = hex.EncodeToString(newAcc.Address[:]) 116 | a.Password = pw 117 | a.KeyStore, err = getKeyStore(a) 118 | if err != nil { 119 | return err 120 | } 121 | os.RemoveAll(contractDir) 122 | return nil 123 | } 124 | 125 | func newContractAuthSession(account AccountConfig, contractID string) (*contract.KillCordSession, error) { 126 | conn, err := ethclient.Dial(ethereumRPCPath) 127 | if err != nil { 128 | return &contract.KillCordSession{}, fmt.Errorf("Failed to connect to the Ethereum client: %v", err) 129 | } 130 | auth, err := bind.NewTransactor(strings.NewReader(account.KeyStore), account.Password) 131 | if err != nil { 132 | return &contract.KillCordSession{}, fmt.Errorf("Failed to create authorized transactor: %v", err) 133 | } 134 | killcord, err := contract.NewKillCord(common.HexToAddress("0x"+contractID), conn) 135 | if err != nil { 136 | return &contract.KillCordSession{}, fmt.Errorf("Failed to instantiate a killcord contract: %v", err) 137 | } 138 | return &contract.KillCordSession{ 139 | Contract: killcord, 140 | CallOpts: bind.CallOpts{ 141 | Pending: true, 142 | }, 143 | TransactOpts: bind.TransactOpts{ 144 | From: auth.From, 145 | Signer: auth.Signer, 146 | }, 147 | }, nil 148 | } 149 | 150 | func newContractCallerSession(contractID string) (*contract.KillCordSession, error) { 151 | conn, err := ethclient.Dial(ethereumRPCPath) 152 | if err != nil { 153 | return &contract.KillCordSession{}, fmt.Errorf("Failed to connect to the Ethereum client: %v", err) 154 | } 155 | killcord, err := contract.NewKillCord(common.HexToAddress("0x"+contractID), conn) 156 | if err != nil { 157 | return &contract.KillCordSession{}, fmt.Errorf("Failed to instantiate a killcord contract: %v", err) 158 | } 159 | return &contract.KillCordSession{ 160 | Contract: killcord, 161 | CallOpts: bind.CallOpts{ 162 | Pending: true, 163 | }, 164 | }, nil 165 | } 166 | 167 | // GetLastCheckIn returns a timestamp or error from last checkin 168 | func GetLastCheckIn(contractID string) (time.Time, error) { 169 | session, err := newContractCallerSession(contractID) 170 | if err != nil { 171 | return time.Now(), err 172 | } 173 | timeStamp, err := session.GetLastCheckIn() 174 | if err != nil { 175 | return time.Now(), fmt.Errorf("Failed to get last checkin: %v", err) 176 | } 177 | return time.Unix(timeStamp.Int64(), 0), nil 178 | } 179 | 180 | func GetKey(contractID string) (string, error) { 181 | session, err := newContractCallerSession(contractID) 182 | if err != nil { 183 | return "", err 184 | } 185 | key, err := session.GetKey() 186 | if err != nil { 187 | return "", fmt.Errorf("Failed to get last checkin: %v", err) 188 | } 189 | return key, nil 190 | } 191 | 192 | func GetOwner(contractID string) (string, error) { 193 | session, err := newContractCallerSession(contractID) 194 | if err != nil { 195 | return "", err 196 | } 197 | address, err := session.GetOwner() 198 | if err != nil { 199 | return "", fmt.Errorf("Failed to get last checkin: %v", err) 200 | } 201 | return address.String(), nil 202 | } 203 | 204 | func GetPublisher(contractID string) (string, error) { 205 | session, err := newContractCallerSession(contractID) 206 | if err != nil { 207 | return "", err 208 | } 209 | address, err := session.GetPublisher() 210 | if err != nil { 211 | return "", fmt.Errorf("Failed to get last checkin: %v", err) 212 | } 213 | return address.String(), nil 214 | } 215 | 216 | func GetPayloadEndpoint(contractID string) (string, error) { 217 | session, err := newContractCallerSession(contractID) 218 | if err != nil { 219 | return "", err 220 | } 221 | endpoint, err := session.GetPayloadEndpoint() 222 | if err != nil { 223 | return "", fmt.Errorf("Failed to get last checkin: %v", err) 224 | } 225 | return endpoint, nil 226 | } 227 | 228 | // Runs a simple checkin to the contract with the owner account. 229 | // TODO: support options for confirming checkin, not just submitting it 230 | func CheckIn(account AccountConfig, contractID string) error { 231 | session, err := newContractAuthSession(account, contractID) 232 | if err != nil { 233 | return err 234 | } 235 | if _, err = session.CheckIn(); err != nil { 236 | return fmt.Errorf("Failed to set Endpoint: %v", err) 237 | } 238 | fmt.Println("checkin successfully submitted") 239 | return nil 240 | } 241 | 242 | func (s *Session) CheckIn() error { 243 | if err := CheckIn(s.Config.Contract.Owner, s.Config.Contract.ID); err != nil { 244 | return err 245 | } 246 | return nil 247 | } 248 | 249 | func SetKey(account AccountConfig, contractID string, secret string) error { 250 | session, err := newContractAuthSession(account, contractID) 251 | if err != nil { 252 | return err 253 | } 254 | if _, err := session.SetKey(secret); err != nil { 255 | return fmt.Errorf("Failed to set Publishable Key: %v", err) 256 | } 257 | fmt.Printf("key publication submitted with %v\n", account.Address) 258 | return nil 259 | } 260 | 261 | func KillContract(account AccountConfig, contractID string) error { 262 | session, err := newContractAuthSession(account, contractID) 263 | if err != nil { 264 | return err 265 | } 266 | if _, err := session.Kill(); err != nil { 267 | return fmt.Errorf("Failed to set Endpoint: %v", err) 268 | } 269 | fmt.Println("contract kill submitted") 270 | return nil 271 | } 272 | 273 | func (s *Session) KillContract() error { 274 | if err := KillContract(s.Config.Contract.Owner, s.Config.Contract.ID); err != nil { 275 | return err 276 | } 277 | return nil 278 | } 279 | 280 | func SetPayloadEndpoint(account AccountConfig, contractID string, payloadID string) error { 281 | session, err := newContractAuthSession(account, contractID) 282 | if err != nil { 283 | return err 284 | } 285 | if _, err := session.SetPayloadEndpoint(payloadID); err != nil { 286 | return fmt.Errorf("Failed to set Endpoint: %v", err) 287 | } 288 | fmt.Println("payload endpoint successfully submitted to contract") 289 | return nil 290 | } 291 | 292 | func (s *Session) DeployContract() error { 293 | if s.Config.Contract.ID != "" { 294 | return fmt.Errorf("contract 0x%v already deployed, skipping", s.Config.Contract.ID) 295 | } 296 | conn, err := ethclient.Dial(ethereumRPCPath) 297 | if err != nil { 298 | log.Fatalf("Failed to connect to the Ethereum client: %v", err) 299 | return err 300 | } 301 | auth, err := bind.NewTransactor(strings.NewReader(s.Config.Contract.Owner.KeyStore), s.Config.Contract.Owner.Password) 302 | if err != nil { 303 | log.Fatalf("Failed to create authorized transactor: %v", err) 304 | return err 305 | } 306 | // TODO: this was set arbitrarily, should dive into this more 307 | // auth.GasLimit = big.NewInt(50000) 308 | // auth.GasPrice = big.NewInt(10) 309 | publisher := common.HexToAddress("0x" + s.Config.Contract.Publisher.Address) 310 | address, tx, _, err := contract.DeployKillCord(auth, conn, publisher) 311 | if err != nil { 312 | log.Fatalf("Failed to deploy new killcord contract: %v", err) 313 | return err 314 | } 315 | fmt.Printf("Contract pending deploy: 0x%x\n", address) 316 | fmt.Printf("Transaction waiting to be mined: 0x%x\n\n", tx.Hash()) 317 | s.Config.Contract.ID = hex.EncodeToString(address[:]) 318 | return nil 319 | } 320 | 321 | func getBalance(account string) float64 { 322 | conn, err := ethclient.Dial(ethereumRPCPath) 323 | if err != nil { 324 | log.Fatalf("Failed to connect to the Ethereum client: %v", err) 325 | } 326 | a := common.HexToAddress("0x" + account) 327 | balance, err := conn.BalanceAt(context.TODO(), a, nil) 328 | if err != nil { 329 | log.Fatalf("balance check failed %v\n", err) 330 | } 331 | b := balance 332 | return weiToETH(b) 333 | } 334 | 335 | func getKeyStore(account *AccountConfig) (string, error) { 336 | var file string 337 | files, err := filepath.Glob(relativeKeyStorePath + "/*") 338 | if err != nil { 339 | return "", err 340 | } 341 | for _, f := range files { 342 | if strings.Contains(f, account.Address) { 343 | file = f 344 | break 345 | } 346 | } 347 | if file == "" { 348 | return "", errors.New("No Contract Account Found") 349 | } 350 | 351 | content, err := ioutil.ReadFile(file) 352 | if err != nil { 353 | return "", err 354 | } 355 | return string(content), nil 356 | } 357 | -------------------------------------------------------------------------------- /contract/killcord.abi: -------------------------------------------------------------------------------- 1 | [{"inputs":[{"internalType":"address","name":"p","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"checkIn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getKey","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPayloadEndpoint","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPublisher","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"k","type":"string"}],"name":"setKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"s","type":"string"}],"name":"setPayloadEndpoint","outputs":[],"stateMutability":"nonpayable","type":"function"}] -------------------------------------------------------------------------------- /contract/killcord.bin: -------------------------------------------------------------------------------- 1 | 608060405234801561001057600080fd5b50604051610c95380380610c958339818101604052602081101561003357600080fd5b810190808051906020019092919050505033600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040518060400160405280600581526020017f302e302e3100000000000000000000000000000000000000000000000000000081525060009080519060200190610111929190610189565b5061012061012660201b60201c565b50610234565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461018057600080fd5b42600381905550565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826101bf5760008555610206565b82601f106101d857805160ff1916838001178555610206565b82800160010185558215610206579182015b828111156102055782518255916020019190600101906101ea565b5b5090506102139190610217565b5090565b5b80821115610230576000816000905550600101610218565b5090565b610a52806102436000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c80638f4f106e116100665780638f4f106e146101f15780639f417563146102ac578063af42d1061461032f578063b1bedda3146103ea578063dbf4ab4e146104085761009e565b80630d8e6e2c146100a3578063183ff0851461012657806341c0e1b51461013057806382678dd61461013a578063893d20e8146101bd575b600080fd5b6100ab61043c565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100eb5780820151818401526020810190506100d0565b50505050905090810190601f1680156101185780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61012e6104de565b005b610138610541565b005b6101426105d6565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610182578082015181840152602081019050610167565b50505050905090810190601f1680156101af5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101c5610678565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6102aa6004803603602081101561020757600080fd5b810190808035906020019064010000000081111561022457600080fd5b82018360208201111561023657600080fd5b8035906020019184600183028401116401000000008311171561025857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506106a2565b005b6102b4610767565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102f45780820151818401526020810190506102d9565b50505050905090810190601f1680156103215780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103e86004803603602081101561034557600080fd5b810190808035906020019064010000000081111561036257600080fd5b82018360208201111561037457600080fd5b8035906020019184600183028401116401000000008311171561039657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610809565b005b6103f261093d565b6040518082815260200191505060405180910390f35b610410610947565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b606060008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156104d45780601f106104a9576101008083540402835291602001916104d4565b820191906000526020600020905b8154815290600101906020018083116104b757829003601f168201915b5050505050905090565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461053857600080fd5b42600381905550565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461059b57600080fd5b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b606060018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561066e5780601f106106435761010080835404028352916020019161066e565b820191906000526020600020905b81548152906001019060200180831161065157829003601f168201915b5050505050905090565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106fc57600080fd5b60006102009050808251111561071157600080fd5b60001515600560159054906101000a900460ff1615151461073157600080fd5b8160029080519060200190610747929190610971565b506001600560156101000a81548160ff0219169083151502179055505050565b606060028054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156107ff5780601f106107d4576101008083540402835291602001916107ff565b820191906000526020600020905b8154815290600101906020018083116107e257829003601f168201915b5050505050905090565b6000600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561086657600190505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156108c157600190505b60011515811515146108d257600080fd5b60006080905080835111156108e657600080fd5b60001515600560149054906101000a900460ff1615151461090657600080fd5b826001908051906020019061091c929190610971565b506001600560146101000a81548160ff021916908315150217905550505050565b6000600354905090565b6000600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826109a757600085556109ee565b82601f106109c057805160ff19168380011785556109ee565b828001600101855582156109ee579182015b828111156109ed5782518255916020019190600101906109d2565b5b5090506109fb91906109ff565b5090565b5b80821115610a18576000816000905550600101610a00565b509056fea264697066735822122022cdd092195489e25280d8a632a28378c0025b74da2dcdd7e59a77bcb0b0565564736f6c63430007050033 -------------------------------------------------------------------------------- /contract/killcord.go: -------------------------------------------------------------------------------- 1 | // Code generated - DO NOT EDIT. 2 | // This file is a generated binding and any manual changes will be lost. 3 | 4 | package contract 5 | 6 | import ( 7 | "math/big" 8 | "strings" 9 | 10 | ethereum "github.com/ethereum/go-ethereum" 11 | "github.com/ethereum/go-ethereum/accounts/abi" 12 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 13 | "github.com/ethereum/go-ethereum/common" 14 | "github.com/ethereum/go-ethereum/core/types" 15 | "github.com/ethereum/go-ethereum/event" 16 | ) 17 | 18 | // Reference imports to suppress errors if they are not otherwise used. 19 | var ( 20 | _ = big.NewInt 21 | _ = strings.NewReader 22 | _ = ethereum.NotFound 23 | _ = bind.Bind 24 | _ = common.Big1 25 | _ = types.BloomLookup 26 | _ = event.NewSubscription 27 | ) 28 | 29 | // KillCordABI is the input ABI used to generate the binding from. 30 | const KillCordABI = "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"p\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"checkIn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLastCheckIn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPayloadEndpoint\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPublisher\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"kill\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"k\",\"type\":\"string\"}],\"name\":\"setKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"s\",\"type\":\"string\"}],\"name\":\"setPayloadEndpoint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" 31 | 32 | // KillCordBin is the compiled bytecode used for deploying new contracts. 33 | var KillCordBin = "0x608060405234801561001057600080fd5b50604051610c95380380610c958339818101604052602081101561003357600080fd5b810190808051906020019092919050505033600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040518060400160405280600581526020017f302e302e3100000000000000000000000000000000000000000000000000000081525060009080519060200190610111929190610189565b5061012061012660201b60201c565b50610234565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461018057600080fd5b42600381905550565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826101bf5760008555610206565b82601f106101d857805160ff1916838001178555610206565b82800160010185558215610206579182015b828111156102055782518255916020019190600101906101ea565b5b5090506102139190610217565b5090565b5b80821115610230576000816000905550600101610218565b5090565b610a52806102436000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c80638f4f106e116100665780638f4f106e146101f15780639f417563146102ac578063af42d1061461032f578063b1bedda3146103ea578063dbf4ab4e146104085761009e565b80630d8e6e2c146100a3578063183ff0851461012657806341c0e1b51461013057806382678dd61461013a578063893d20e8146101bd575b600080fd5b6100ab61043c565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100eb5780820151818401526020810190506100d0565b50505050905090810190601f1680156101185780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61012e6104de565b005b610138610541565b005b6101426105d6565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610182578082015181840152602081019050610167565b50505050905090810190601f1680156101af5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101c5610678565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6102aa6004803603602081101561020757600080fd5b810190808035906020019064010000000081111561022457600080fd5b82018360208201111561023657600080fd5b8035906020019184600183028401116401000000008311171561025857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506106a2565b005b6102b4610767565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102f45780820151818401526020810190506102d9565b50505050905090810190601f1680156103215780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103e86004803603602081101561034557600080fd5b810190808035906020019064010000000081111561036257600080fd5b82018360208201111561037457600080fd5b8035906020019184600183028401116401000000008311171561039657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610809565b005b6103f261093d565b6040518082815260200191505060405180910390f35b610410610947565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b606060008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156104d45780601f106104a9576101008083540402835291602001916104d4565b820191906000526020600020905b8154815290600101906020018083116104b757829003601f168201915b5050505050905090565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461053857600080fd5b42600381905550565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461059b57600080fd5b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b606060018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561066e5780601f106106435761010080835404028352916020019161066e565b820191906000526020600020905b81548152906001019060200180831161065157829003601f168201915b5050505050905090565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106fc57600080fd5b60006102009050808251111561071157600080fd5b60001515600560159054906101000a900460ff1615151461073157600080fd5b8160029080519060200190610747929190610971565b506001600560156101000a81548160ff0219169083151502179055505050565b606060028054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156107ff5780601f106107d4576101008083540402835291602001916107ff565b820191906000526020600020905b8154815290600101906020018083116107e257829003601f168201915b5050505050905090565b6000600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561086657600190505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156108c157600190505b60011515811515146108d257600080fd5b60006080905080835111156108e657600080fd5b60001515600560149054906101000a900460ff1615151461090657600080fd5b826001908051906020019061091c929190610971565b506001600560146101000a81548160ff021916908315150217905550505050565b6000600354905090565b6000600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826109a757600085556109ee565b82601f106109c057805160ff19168380011785556109ee565b828001600101855582156109ee579182015b828111156109ed5782518255916020019190600101906109d2565b5b5090506109fb91906109ff565b5090565b5b80821115610a18576000816000905550600101610a00565b509056fea264697066735822122022cdd092195489e25280d8a632a28378c0025b74da2dcdd7e59a77bcb0b0565564736f6c63430007050033" 34 | 35 | // DeployKillCord deploys a new Ethereum contract, binding an instance of KillCord to it. 36 | func DeployKillCord(auth *bind.TransactOpts, backend bind.ContractBackend, p common.Address) (common.Address, *types.Transaction, *KillCord, error) { 37 | parsed, err := abi.JSON(strings.NewReader(KillCordABI)) 38 | if err != nil { 39 | return common.Address{}, nil, nil, err 40 | } 41 | 42 | address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(KillCordBin), backend, p) 43 | if err != nil { 44 | return common.Address{}, nil, nil, err 45 | } 46 | return address, tx, &KillCord{KillCordCaller: KillCordCaller{contract: contract}, KillCordTransactor: KillCordTransactor{contract: contract}, KillCordFilterer: KillCordFilterer{contract: contract}}, nil 47 | } 48 | 49 | // KillCord is an auto generated Go binding around an Ethereum contract. 50 | type KillCord struct { 51 | KillCordCaller // Read-only binding to the contract 52 | KillCordTransactor // Write-only binding to the contract 53 | KillCordFilterer // Log filterer for contract events 54 | } 55 | 56 | // KillCordCaller is an auto generated read-only Go binding around an Ethereum contract. 57 | type KillCordCaller struct { 58 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 59 | } 60 | 61 | // KillCordTransactor is an auto generated write-only Go binding around an Ethereum contract. 62 | type KillCordTransactor struct { 63 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 64 | } 65 | 66 | // KillCordFilterer is an auto generated log filtering Go binding around an Ethereum contract events. 67 | type KillCordFilterer struct { 68 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 69 | } 70 | 71 | // KillCordSession is an auto generated Go binding around an Ethereum contract, 72 | // with pre-set call and transact options. 73 | type KillCordSession struct { 74 | Contract *KillCord // Generic contract binding to set the session for 75 | CallOpts bind.CallOpts // Call options to use throughout this session 76 | TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session 77 | } 78 | 79 | // KillCordCallerSession is an auto generated read-only Go binding around an Ethereum contract, 80 | // with pre-set call options. 81 | type KillCordCallerSession struct { 82 | Contract *KillCordCaller // Generic contract caller binding to set the session for 83 | CallOpts bind.CallOpts // Call options to use throughout this session 84 | } 85 | 86 | // KillCordTransactorSession is an auto generated write-only Go binding around an Ethereum contract, 87 | // with pre-set transact options. 88 | type KillCordTransactorSession struct { 89 | Contract *KillCordTransactor // Generic contract transactor binding to set the session for 90 | TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session 91 | } 92 | 93 | // KillCordRaw is an auto generated low-level Go binding around an Ethereum contract. 94 | type KillCordRaw struct { 95 | Contract *KillCord // Generic contract binding to access the raw methods on 96 | } 97 | 98 | // KillCordCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. 99 | type KillCordCallerRaw struct { 100 | Contract *KillCordCaller // Generic read-only contract binding to access the raw methods on 101 | } 102 | 103 | // KillCordTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. 104 | type KillCordTransactorRaw struct { 105 | Contract *KillCordTransactor // Generic write-only contract binding to access the raw methods on 106 | } 107 | 108 | // NewKillCord creates a new instance of KillCord, bound to a specific deployed contract. 109 | func NewKillCord(address common.Address, backend bind.ContractBackend) (*KillCord, error) { 110 | contract, err := bindKillCord(address, backend, backend, backend) 111 | if err != nil { 112 | return nil, err 113 | } 114 | return &KillCord{KillCordCaller: KillCordCaller{contract: contract}, KillCordTransactor: KillCordTransactor{contract: contract}, KillCordFilterer: KillCordFilterer{contract: contract}}, nil 115 | } 116 | 117 | // NewKillCordCaller creates a new read-only instance of KillCord, bound to a specific deployed contract. 118 | func NewKillCordCaller(address common.Address, caller bind.ContractCaller) (*KillCordCaller, error) { 119 | contract, err := bindKillCord(address, caller, nil, nil) 120 | if err != nil { 121 | return nil, err 122 | } 123 | return &KillCordCaller{contract: contract}, nil 124 | } 125 | 126 | // NewKillCordTransactor creates a new write-only instance of KillCord, bound to a specific deployed contract. 127 | func NewKillCordTransactor(address common.Address, transactor bind.ContractTransactor) (*KillCordTransactor, error) { 128 | contract, err := bindKillCord(address, nil, transactor, nil) 129 | if err != nil { 130 | return nil, err 131 | } 132 | return &KillCordTransactor{contract: contract}, nil 133 | } 134 | 135 | // NewKillCordFilterer creates a new log filterer instance of KillCord, bound to a specific deployed contract. 136 | func NewKillCordFilterer(address common.Address, filterer bind.ContractFilterer) (*KillCordFilterer, error) { 137 | contract, err := bindKillCord(address, nil, nil, filterer) 138 | if err != nil { 139 | return nil, err 140 | } 141 | return &KillCordFilterer{contract: contract}, nil 142 | } 143 | 144 | // bindKillCord binds a generic wrapper to an already deployed contract. 145 | func bindKillCord(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { 146 | parsed, err := abi.JSON(strings.NewReader(KillCordABI)) 147 | if err != nil { 148 | return nil, err 149 | } 150 | return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil 151 | } 152 | 153 | // Call invokes the (constant) contract method with params as input values and 154 | // sets the output to result. The result type might be a single field for simple 155 | // returns, a slice of interfaces for anonymous returns and a struct for named 156 | // returns. 157 | func (_KillCord *KillCordRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { 158 | return _KillCord.Contract.KillCordCaller.contract.Call(opts, result, method, params...) 159 | } 160 | 161 | // Transfer initiates a plain transaction to move funds to the contract, calling 162 | // its default method if one is available. 163 | func (_KillCord *KillCordRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { 164 | return _KillCord.Contract.KillCordTransactor.contract.Transfer(opts) 165 | } 166 | 167 | // Transact invokes the (paid) contract method with params as input values. 168 | func (_KillCord *KillCordRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { 169 | return _KillCord.Contract.KillCordTransactor.contract.Transact(opts, method, params...) 170 | } 171 | 172 | // Call invokes the (constant) contract method with params as input values and 173 | // sets the output to result. The result type might be a single field for simple 174 | // returns, a slice of interfaces for anonymous returns and a struct for named 175 | // returns. 176 | func (_KillCord *KillCordCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { 177 | return _KillCord.Contract.contract.Call(opts, result, method, params...) 178 | } 179 | 180 | // Transfer initiates a plain transaction to move funds to the contract, calling 181 | // its default method if one is available. 182 | func (_KillCord *KillCordTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { 183 | return _KillCord.Contract.contract.Transfer(opts) 184 | } 185 | 186 | // Transact invokes the (paid) contract method with params as input values. 187 | func (_KillCord *KillCordTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { 188 | return _KillCord.Contract.contract.Transact(opts, method, params...) 189 | } 190 | 191 | // GetKey is a free data retrieval call binding the contract method 0x82678dd6. 192 | // 193 | // Solidity: function getKey() view returns(string) 194 | func (_KillCord *KillCordCaller) GetKey(opts *bind.CallOpts) (string, error) { 195 | var out []interface{} 196 | err := _KillCord.contract.Call(opts, &out, "getKey") 197 | 198 | if err != nil { 199 | return *new(string), err 200 | } 201 | 202 | out0 := *abi.ConvertType(out[0], new(string)).(*string) 203 | 204 | return out0, err 205 | 206 | } 207 | 208 | // GetKey is a free data retrieval call binding the contract method 0x82678dd6. 209 | // 210 | // Solidity: function getKey() view returns(string) 211 | func (_KillCord *KillCordSession) GetKey() (string, error) { 212 | return _KillCord.Contract.GetKey(&_KillCord.CallOpts) 213 | } 214 | 215 | // GetKey is a free data retrieval call binding the contract method 0x82678dd6. 216 | // 217 | // Solidity: function getKey() view returns(string) 218 | func (_KillCord *KillCordCallerSession) GetKey() (string, error) { 219 | return _KillCord.Contract.GetKey(&_KillCord.CallOpts) 220 | } 221 | 222 | // GetLastCheckIn is a free data retrieval call binding the contract method 0xb1bedda3. 223 | // 224 | // Solidity: function getLastCheckIn() view returns(uint256) 225 | func (_KillCord *KillCordCaller) GetLastCheckIn(opts *bind.CallOpts) (*big.Int, error) { 226 | var out []interface{} 227 | err := _KillCord.contract.Call(opts, &out, "getLastCheckIn") 228 | 229 | if err != nil { 230 | return *new(*big.Int), err 231 | } 232 | 233 | out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) 234 | 235 | return out0, err 236 | 237 | } 238 | 239 | // GetLastCheckIn is a free data retrieval call binding the contract method 0xb1bedda3. 240 | // 241 | // Solidity: function getLastCheckIn() view returns(uint256) 242 | func (_KillCord *KillCordSession) GetLastCheckIn() (*big.Int, error) { 243 | return _KillCord.Contract.GetLastCheckIn(&_KillCord.CallOpts) 244 | } 245 | 246 | // GetLastCheckIn is a free data retrieval call binding the contract method 0xb1bedda3. 247 | // 248 | // Solidity: function getLastCheckIn() view returns(uint256) 249 | func (_KillCord *KillCordCallerSession) GetLastCheckIn() (*big.Int, error) { 250 | return _KillCord.Contract.GetLastCheckIn(&_KillCord.CallOpts) 251 | } 252 | 253 | // GetOwner is a free data retrieval call binding the contract method 0x893d20e8. 254 | // 255 | // Solidity: function getOwner() view returns(address) 256 | func (_KillCord *KillCordCaller) GetOwner(opts *bind.CallOpts) (common.Address, error) { 257 | var out []interface{} 258 | err := _KillCord.contract.Call(opts, &out, "getOwner") 259 | 260 | if err != nil { 261 | return *new(common.Address), err 262 | } 263 | 264 | out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) 265 | 266 | return out0, err 267 | 268 | } 269 | 270 | // GetOwner is a free data retrieval call binding the contract method 0x893d20e8. 271 | // 272 | // Solidity: function getOwner() view returns(address) 273 | func (_KillCord *KillCordSession) GetOwner() (common.Address, error) { 274 | return _KillCord.Contract.GetOwner(&_KillCord.CallOpts) 275 | } 276 | 277 | // GetOwner is a free data retrieval call binding the contract method 0x893d20e8. 278 | // 279 | // Solidity: function getOwner() view returns(address) 280 | func (_KillCord *KillCordCallerSession) GetOwner() (common.Address, error) { 281 | return _KillCord.Contract.GetOwner(&_KillCord.CallOpts) 282 | } 283 | 284 | // GetPayloadEndpoint is a free data retrieval call binding the contract method 0x9f417563. 285 | // 286 | // Solidity: function getPayloadEndpoint() view returns(string) 287 | func (_KillCord *KillCordCaller) GetPayloadEndpoint(opts *bind.CallOpts) (string, error) { 288 | var out []interface{} 289 | err := _KillCord.contract.Call(opts, &out, "getPayloadEndpoint") 290 | 291 | if err != nil { 292 | return *new(string), err 293 | } 294 | 295 | out0 := *abi.ConvertType(out[0], new(string)).(*string) 296 | 297 | return out0, err 298 | 299 | } 300 | 301 | // GetPayloadEndpoint is a free data retrieval call binding the contract method 0x9f417563. 302 | // 303 | // Solidity: function getPayloadEndpoint() view returns(string) 304 | func (_KillCord *KillCordSession) GetPayloadEndpoint() (string, error) { 305 | return _KillCord.Contract.GetPayloadEndpoint(&_KillCord.CallOpts) 306 | } 307 | 308 | // GetPayloadEndpoint is a free data retrieval call binding the contract method 0x9f417563. 309 | // 310 | // Solidity: function getPayloadEndpoint() view returns(string) 311 | func (_KillCord *KillCordCallerSession) GetPayloadEndpoint() (string, error) { 312 | return _KillCord.Contract.GetPayloadEndpoint(&_KillCord.CallOpts) 313 | } 314 | 315 | // GetPublisher is a free data retrieval call binding the contract method 0xdbf4ab4e. 316 | // 317 | // Solidity: function getPublisher() view returns(address) 318 | func (_KillCord *KillCordCaller) GetPublisher(opts *bind.CallOpts) (common.Address, error) { 319 | var out []interface{} 320 | err := _KillCord.contract.Call(opts, &out, "getPublisher") 321 | 322 | if err != nil { 323 | return *new(common.Address), err 324 | } 325 | 326 | out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) 327 | 328 | return out0, err 329 | 330 | } 331 | 332 | // GetPublisher is a free data retrieval call binding the contract method 0xdbf4ab4e. 333 | // 334 | // Solidity: function getPublisher() view returns(address) 335 | func (_KillCord *KillCordSession) GetPublisher() (common.Address, error) { 336 | return _KillCord.Contract.GetPublisher(&_KillCord.CallOpts) 337 | } 338 | 339 | // GetPublisher is a free data retrieval call binding the contract method 0xdbf4ab4e. 340 | // 341 | // Solidity: function getPublisher() view returns(address) 342 | func (_KillCord *KillCordCallerSession) GetPublisher() (common.Address, error) { 343 | return _KillCord.Contract.GetPublisher(&_KillCord.CallOpts) 344 | } 345 | 346 | // GetVersion is a free data retrieval call binding the contract method 0x0d8e6e2c. 347 | // 348 | // Solidity: function getVersion() view returns(string) 349 | func (_KillCord *KillCordCaller) GetVersion(opts *bind.CallOpts) (string, error) { 350 | var out []interface{} 351 | err := _KillCord.contract.Call(opts, &out, "getVersion") 352 | 353 | if err != nil { 354 | return *new(string), err 355 | } 356 | 357 | out0 := *abi.ConvertType(out[0], new(string)).(*string) 358 | 359 | return out0, err 360 | 361 | } 362 | 363 | // GetVersion is a free data retrieval call binding the contract method 0x0d8e6e2c. 364 | // 365 | // Solidity: function getVersion() view returns(string) 366 | func (_KillCord *KillCordSession) GetVersion() (string, error) { 367 | return _KillCord.Contract.GetVersion(&_KillCord.CallOpts) 368 | } 369 | 370 | // GetVersion is a free data retrieval call binding the contract method 0x0d8e6e2c. 371 | // 372 | // Solidity: function getVersion() view returns(string) 373 | func (_KillCord *KillCordCallerSession) GetVersion() (string, error) { 374 | return _KillCord.Contract.GetVersion(&_KillCord.CallOpts) 375 | } 376 | 377 | // CheckIn is a paid mutator transaction binding the contract method 0x183ff085. 378 | // 379 | // Solidity: function checkIn() returns() 380 | func (_KillCord *KillCordTransactor) CheckIn(opts *bind.TransactOpts) (*types.Transaction, error) { 381 | return _KillCord.contract.Transact(opts, "checkIn") 382 | } 383 | 384 | // CheckIn is a paid mutator transaction binding the contract method 0x183ff085. 385 | // 386 | // Solidity: function checkIn() returns() 387 | func (_KillCord *KillCordSession) CheckIn() (*types.Transaction, error) { 388 | return _KillCord.Contract.CheckIn(&_KillCord.TransactOpts) 389 | } 390 | 391 | // CheckIn is a paid mutator transaction binding the contract method 0x183ff085. 392 | // 393 | // Solidity: function checkIn() returns() 394 | func (_KillCord *KillCordTransactorSession) CheckIn() (*types.Transaction, error) { 395 | return _KillCord.Contract.CheckIn(&_KillCord.TransactOpts) 396 | } 397 | 398 | // Kill is a paid mutator transaction binding the contract method 0x41c0e1b5. 399 | // 400 | // Solidity: function kill() returns() 401 | func (_KillCord *KillCordTransactor) Kill(opts *bind.TransactOpts) (*types.Transaction, error) { 402 | return _KillCord.contract.Transact(opts, "kill") 403 | } 404 | 405 | // Kill is a paid mutator transaction binding the contract method 0x41c0e1b5. 406 | // 407 | // Solidity: function kill() returns() 408 | func (_KillCord *KillCordSession) Kill() (*types.Transaction, error) { 409 | return _KillCord.Contract.Kill(&_KillCord.TransactOpts) 410 | } 411 | 412 | // Kill is a paid mutator transaction binding the contract method 0x41c0e1b5. 413 | // 414 | // Solidity: function kill() returns() 415 | func (_KillCord *KillCordTransactorSession) Kill() (*types.Transaction, error) { 416 | return _KillCord.Contract.Kill(&_KillCord.TransactOpts) 417 | } 418 | 419 | // SetKey is a paid mutator transaction binding the contract method 0xaf42d106. 420 | // 421 | // Solidity: function setKey(string k) returns() 422 | func (_KillCord *KillCordTransactor) SetKey(opts *bind.TransactOpts, k string) (*types.Transaction, error) { 423 | return _KillCord.contract.Transact(opts, "setKey", k) 424 | } 425 | 426 | // SetKey is a paid mutator transaction binding the contract method 0xaf42d106. 427 | // 428 | // Solidity: function setKey(string k) returns() 429 | func (_KillCord *KillCordSession) SetKey(k string) (*types.Transaction, error) { 430 | return _KillCord.Contract.SetKey(&_KillCord.TransactOpts, k) 431 | } 432 | 433 | // SetKey is a paid mutator transaction binding the contract method 0xaf42d106. 434 | // 435 | // Solidity: function setKey(string k) returns() 436 | func (_KillCord *KillCordTransactorSession) SetKey(k string) (*types.Transaction, error) { 437 | return _KillCord.Contract.SetKey(&_KillCord.TransactOpts, k) 438 | } 439 | 440 | // SetPayloadEndpoint is a paid mutator transaction binding the contract method 0x8f4f106e. 441 | // 442 | // Solidity: function setPayloadEndpoint(string s) returns() 443 | func (_KillCord *KillCordTransactor) SetPayloadEndpoint(opts *bind.TransactOpts, s string) (*types.Transaction, error) { 444 | return _KillCord.contract.Transact(opts, "setPayloadEndpoint", s) 445 | } 446 | 447 | // SetPayloadEndpoint is a paid mutator transaction binding the contract method 0x8f4f106e. 448 | // 449 | // Solidity: function setPayloadEndpoint(string s) returns() 450 | func (_KillCord *KillCordSession) SetPayloadEndpoint(s string) (*types.Transaction, error) { 451 | return _KillCord.Contract.SetPayloadEndpoint(&_KillCord.TransactOpts, s) 452 | } 453 | 454 | // SetPayloadEndpoint is a paid mutator transaction binding the contract method 0x8f4f106e. 455 | // 456 | // Solidity: function setPayloadEndpoint(string s) returns() 457 | func (_KillCord *KillCordTransactorSession) SetPayloadEndpoint(s string) (*types.Transaction, error) { 458 | return _KillCord.Contract.SetPayloadEndpoint(&_KillCord.TransactOpts, s) 459 | } 460 | -------------------------------------------------------------------------------- /contract/killcord.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Unlicense 2 | pragma solidity ^0.7.0; 3 | 4 | contract killcord { 5 | string version; 6 | string publishedKey; 7 | string payloadEndpoint; 8 | uint lastCheckIn; 9 | address payable owner; 10 | address publisher; 11 | bool lockPublishedKey; 12 | bool lockPayloadEndpoint; 13 | 14 | // set the `owner` of the contract and log first `checkIn` 15 | constructor(address p) { 16 | owner = msg.sender; 17 | publisher = p; 18 | version = "0.0.1"; 19 | checkIn(); 20 | } 21 | 22 | // a function modifier used to restrict most write functions to only 23 | // the contract owner 24 | modifier onlyOwner { 25 | require(msg.sender == owner); 26 | _; 27 | } 28 | 29 | // a function modifier used to restrict publishing the key to only 30 | // the owner or publisher addresses 31 | modifier onlyOwnerOrPublisher { 32 | bool ok = false; 33 | if (msg.sender == publisher) { 34 | ok = true; 35 | } 36 | if (msg.sender == owner) { 37 | ok = true; 38 | } 39 | require(ok == true); 40 | _; 41 | } 42 | 43 | // This function is restricted to work with only the contract owner. 44 | // friends don't let friends deploy contracts that can't be killed 45 | function kill() public onlyOwner { 46 | selfdestruct(owner); 47 | } 48 | 49 | // This function is restricted to work with only the contract owner. 50 | // `block.timestamp` is known to tolerate datestamp drift of up to 51 | // 900 seconds at the time of this writing, consider then when 52 | // setting TTL thresholds for the publisher. 53 | function checkIn() public onlyOwner { 54 | lastCheckIn = block.timestamp; 55 | } 56 | 57 | // Outputs the `uint` for the last `block.timestamp` 58 | // that registered to this contract on the blockchain. 59 | function getLastCheckIn() public view returns (uint) { 60 | return lastCheckIn; 61 | } 62 | 63 | // Outputs the `string` for the last `block.timestamp` 64 | // that registered to this contract on the blockchain. 65 | function getPayloadEndpoint() public view returns (string memory) { 66 | return payloadEndpoint; 67 | } 68 | 69 | // This function is restricted to work with only the contract owner. 70 | // Sets the Payload Endpoint after checking max length of the string. 71 | // sets lockPayloadEndpoint to TRUE so that once set, this value can 72 | // not be changed. 73 | function setPayloadEndpoint(string memory s) public onlyOwner { 74 | uint max = 512; 75 | require(bytes(s).length <= max); 76 | require(lockPayloadEndpoint == false); 77 | payloadEndpoint = s; 78 | lockPayloadEndpoint = true; 79 | } 80 | 81 | // getKey() simply outputs the `publishedKey` saved to the blockChain 82 | function getKey() public view returns (string memory) { 83 | return publishedKey; 84 | } 85 | 86 | function getOwner() public view returns (address) { 87 | return owner; 88 | } 89 | 90 | function getPublisher() public view returns (address) { 91 | return publisher; 92 | } 93 | 94 | function getVersion() public view returns (string memory) { 95 | return version; 96 | } 97 | 98 | // This function is restricted to work with only the contract owner. 99 | function setKey(string memory k) public onlyOwnerOrPublisher { 100 | uint max = 128; 101 | require(bytes(k).length <= max); 102 | require(lockPublishedKey == false); 103 | publishedKey = k; 104 | lockPublishedKey = true; 105 | } 106 | } -------------------------------------------------------------------------------- /contract_test.go: -------------------------------------------------------------------------------- 1 | package killcord 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestSetEthereumRPCPath(t *testing.T) { 8 | s := New() 9 | s.Init() 10 | if ethereumRPCPath != defaultETHRPCPDev { 11 | t.Fail() 12 | } 13 | if s.Config.Contract.Mode != "testnet" { 14 | t.Fail() 15 | } 16 | s.Config.Contract.Mode = "mainnet" 17 | s.setEthereumRPCPath() 18 | if ethereumRPCPath != defaultETHRPCDProd { 19 | t.Fail() 20 | } 21 | s.Config.Contract.RPCURL = "t1" 22 | s.setEthereumRPCPath() 23 | if ethereumRPCPath != "t1" { 24 | t.Fail() 25 | } 26 | s.Options.Contract.RPCURL = "t2" 27 | s.setEthereumRPCPath() 28 | if ethereumRPCPath != "t2" { 29 | t.Fail() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | killcord-linux-builder: 4 | build: ./ 5 | environment: 6 | - GITHUB_TOKEN 7 | - AWS_SECRET_ACCESS_KEY=${KILLCORD_AWS_SECRET_ACCESS_KEY} 8 | - AWS_ACCESS_KEY_ID=${KILLCORD_AWS_ACCESS_KEY_ID} 9 | - AWS_DEFAULT_REGION=us-east-1 10 | command: ./scripts/build-release.sh -------------------------------------------------------------------------------- /examples/lambda/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "strconv" 6 | 7 | "github.com/aws/aws-lambda-go/lambda" 8 | "github.com/nomasters/killcord" 9 | ) 10 | 11 | func main() { 12 | var opts killcord.ProjectOptions 13 | session := killcord.New() 14 | 15 | opts.Payload.Secret = os.Getenv("KILLCORD_PAYLOAD_SECRET") 16 | opts.Payload.RPCURL = os.Getenv("KILLCORD_PAYLOAD_RPCURL") 17 | opts.Contract.ID = os.Getenv("KILLCORD_CONTRACT_ID") 18 | opts.Contract.RPCURL = os.Getenv("KILLCORD_CONTRACT_RPCURL") 19 | opts.Contract.Publisher.Address = os.Getenv("KILLCORD_CONTRACT_PUBLISHER_ADDRESS") 20 | opts.Contract.Publisher.Password = os.Getenv("KILLCORD_CONTRACT_PUBLISHER_PASSWORD") 21 | opts.Contract.Publisher.KeyStore = os.Getenv("KILLCORD_CONTRACT_PUBLISHER_KEYSTORE") 22 | 23 | // check for dev mode string and set bool 24 | if os.Getenv("KILLCORD_DEV_MODE") == "true" { 25 | opts.DevMode = true 26 | } 27 | 28 | // check for warning threshold and if it exists, convert to int64 29 | if x := os.Getenv("KILLCORD_PUBLISHER_WARNING_THRESHOLD"); x != "" { 30 | y, err := strconv.Atoi(x) 31 | if err == nil { 32 | opts.Publisher.WarningThreshold = int64(y) 33 | } 34 | } 35 | 36 | // check for publish threshold and if it exists, convert to int64 37 | if x := os.Getenv("KILLCORD_PUBLISHER_PUBLISH_THRESHOLD"); x != "" { 38 | y, err := strconv.Atoi(x) 39 | if err == nil { 40 | opts.Publisher.PublishThreshold = int64(y) 41 | } 42 | } 43 | 44 | session.Options = opts 45 | session.Init() 46 | 47 | lambda.Start(session.PublisherLambdaHandler) 48 | } 49 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/nomasters/killcord 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/BurntSushi/toml v0.3.1 7 | github.com/aws/aws-lambda-go v1.20.0 8 | github.com/cheggaaa/pb/v3 v3.0.8 9 | github.com/ethereum/go-ethereum v1.10.17 10 | github.com/ipfs/go-ipfs-api v0.3.0 11 | github.com/mholt/archiver/v3 v3.5.1 12 | github.com/spf13/cobra v1.1.1 13 | github.com/spf13/viper v1.7.1 14 | golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 15 | ) 16 | 17 | require ( 18 | github.com/VividCortex/ewma v1.2.0 // indirect 19 | github.com/andybalholm/brotli v1.0.4 // indirect 20 | github.com/btcsuite/btcd v0.22.0-beta // indirect 21 | github.com/btcsuite/btcd/btcec/v2 v2.1.3 // indirect 22 | github.com/cespare/cp v1.1.1 // indirect 23 | github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect 24 | github.com/deckarep/golang-set v1.8.0 // indirect 25 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect 26 | github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect 27 | github.com/fatih/color v1.13.0 // indirect 28 | github.com/fsnotify/fsnotify v1.4.9 // indirect 29 | github.com/go-ole/go-ole v1.2.6 // indirect 30 | github.com/go-stack/stack v1.8.1 // indirect 31 | github.com/gogo/protobuf v1.3.2 // indirect 32 | github.com/golang/snappy v0.0.4 // indirect 33 | github.com/google/uuid v1.3.0 // indirect 34 | github.com/gorilla/websocket v1.5.0 // indirect 35 | github.com/hashicorp/hcl v1.0.0 // indirect 36 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 37 | github.com/ipfs/go-cid v0.2.0 // indirect 38 | github.com/ipfs/go-ipfs-files v0.1.1 // indirect 39 | github.com/klauspost/compress v1.15.1 // indirect 40 | github.com/klauspost/cpuid/v2 v2.0.12 // indirect 41 | github.com/klauspost/pgzip v1.2.5 // indirect 42 | github.com/libp2p/go-buffer-pool v0.0.2 // indirect 43 | github.com/libp2p/go-flow-metrics v0.0.3 // indirect 44 | github.com/libp2p/go-libp2p-core v0.15.1 // indirect 45 | github.com/libp2p/go-openssl v0.0.7 // indirect 46 | github.com/magiconair/properties v1.8.1 // indirect 47 | github.com/mattn/go-colorable v0.1.12 // indirect 48 | github.com/mattn/go-isatty v0.0.14 // indirect 49 | github.com/mattn/go-runewidth v0.0.13 // indirect 50 | github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect 51 | github.com/minio/sha256-simd v1.0.0 // indirect 52 | github.com/mitchellh/go-homedir v1.1.0 // indirect 53 | github.com/mitchellh/mapstructure v1.4.1 // indirect 54 | github.com/mr-tron/base58 v1.2.0 // indirect 55 | github.com/multiformats/go-base32 v0.0.4 // indirect 56 | github.com/multiformats/go-base36 v0.1.0 // indirect 57 | github.com/multiformats/go-multiaddr v0.5.0 // indirect 58 | github.com/multiformats/go-multibase v0.0.3 // indirect 59 | github.com/multiformats/go-multicodec v0.4.1 // indirect 60 | github.com/multiformats/go-multihash v0.1.0 // indirect 61 | github.com/multiformats/go-varint v0.0.6 // indirect 62 | github.com/nwaples/rardecode v1.1.3 // indirect 63 | github.com/pelletier/go-toml v1.2.0 // indirect 64 | github.com/pierrec/lz4/v4 v4.1.14 // indirect 65 | github.com/rivo/uniseg v0.2.0 // indirect 66 | github.com/rjeczalik/notify v0.9.2 // indirect 67 | github.com/shirou/gopsutil v3.21.11+incompatible // indirect 68 | github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect 69 | github.com/spaolacci/murmur3 v1.1.0 // indirect 70 | github.com/spf13/afero v1.1.2 // indirect 71 | github.com/spf13/cast v1.3.0 // indirect 72 | github.com/spf13/jwalterweatherman v1.0.0 // indirect 73 | github.com/spf13/pflag v1.0.5 // indirect 74 | github.com/subosito/gotenv v1.2.0 // indirect 75 | github.com/tklauser/go-sysconf v0.3.10 // indirect 76 | github.com/tklauser/numcpus v0.4.0 // indirect 77 | github.com/ulikunitz/xz v0.5.10 // indirect 78 | github.com/whyrusleeping/tar-utils v0.0.0-20201201191210-20a61371de5b // indirect 79 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect 80 | github.com/yusufpapurcu/wmi v1.2.2 // indirect 81 | golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect 82 | golang.org/x/text v0.3.7 // indirect 83 | gopkg.in/ini.v1 v1.51.0 // indirect 84 | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect 85 | gopkg.in/yaml.v2 v2.4.0 // indirect 86 | lukechampine.com/blake3 v1.1.7 // indirect 87 | ) 88 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= 5 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 6 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 7 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 8 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 9 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 10 | cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= 11 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 12 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 13 | cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= 14 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 15 | cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= 16 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 17 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 18 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 19 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 20 | collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= 21 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 22 | github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= 23 | github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= 24 | github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= 25 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 26 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 27 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 28 | github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= 29 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 30 | github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= 31 | github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= 32 | github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= 33 | github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= 34 | github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= 35 | github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= 36 | github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= 37 | github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= 38 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 39 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 40 | github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= 41 | github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= 42 | github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= 43 | github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= 44 | github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= 45 | github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= 46 | github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 47 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= 48 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 49 | github.com/aws/aws-lambda-go v1.20.0 h1:ZSweJx/Hy9BoIDXKBEh16vbHH0t0dehnF8MKpMiOWc0= 50 | github.com/aws/aws-lambda-go v1.20.0/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU= 51 | github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= 52 | github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y= 53 | github.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo= 54 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM= 55 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8= 56 | github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4= 57 | github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= 58 | github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= 59 | github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= 60 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 61 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 62 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 63 | github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= 64 | github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= 65 | github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= 66 | github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= 67 | github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo= 68 | github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= 69 | github.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= 70 | github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE= 71 | github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= 72 | github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= 73 | github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= 74 | github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= 75 | github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= 76 | github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= 77 | github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= 78 | github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= 79 | github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= 80 | github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= 81 | github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= 82 | github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= 83 | github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= 84 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 85 | github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= 86 | github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= 87 | github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= 88 | github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= 89 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 90 | github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= 91 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 92 | github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764= 93 | github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= 94 | github.com/cheggaaa/pb/v3 v3.0.8 h1:bC8oemdChbke2FHIIGy9mn4DPJ2caZYQnfbRqwmdCoA= 95 | github.com/cheggaaa/pb/v3 v3.0.8/go.mod h1:UICbiLec/XO6Hw6k+BHEtHeQFzzBH4i2/qk/ow1EJTA= 96 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 97 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 98 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 99 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 100 | github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= 101 | github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= 102 | github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= 103 | github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= 104 | github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 105 | github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 106 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 107 | github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 108 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 109 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 110 | github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= 111 | github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= 112 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 113 | github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= 114 | github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= 115 | github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 116 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 117 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 118 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 119 | github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= 120 | github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= 121 | github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= 122 | github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= 123 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= 124 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= 125 | github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= 126 | github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= 127 | github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= 128 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 129 | github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= 130 | github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= 131 | github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= 132 | github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= 133 | github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= 134 | github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 135 | github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= 136 | github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= 137 | github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= 138 | github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= 139 | github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= 140 | github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= 141 | github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= 142 | github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= 143 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 144 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 145 | github.com/ethereum/go-ethereum v1.10.17 h1:XEcumY+qSr1cZQaWsQs5Kck3FHB0V2RiMHPdTBJ+oT8= 146 | github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0= 147 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 148 | github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= 149 | github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= 150 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= 151 | github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= 152 | github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= 153 | github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= 154 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 155 | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= 156 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 157 | github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= 158 | github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= 159 | github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= 160 | github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= 161 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 162 | github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= 163 | github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= 164 | github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= 165 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 166 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 167 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 168 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 169 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 170 | github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= 171 | github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= 172 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 173 | github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 174 | github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 175 | github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= 176 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 177 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 178 | github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= 179 | github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= 180 | github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 181 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 182 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 183 | github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 184 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 185 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 186 | github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= 187 | github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= 188 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 189 | github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= 190 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 191 | github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 192 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 193 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 194 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 195 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 196 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 197 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 198 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 199 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 200 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 201 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 202 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 203 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 204 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 205 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 206 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 207 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 208 | github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 209 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 210 | github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= 211 | github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 212 | github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= 213 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 214 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 215 | github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= 216 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 217 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 218 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 219 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 220 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 221 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 222 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 223 | github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 224 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 225 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 226 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 227 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 228 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 229 | github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 230 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 231 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 232 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 233 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 234 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= 235 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 236 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 237 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 238 | github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= 239 | github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 240 | github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= 241 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 242 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 243 | github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 244 | github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= 245 | github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= 246 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 247 | github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= 248 | github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= 249 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 250 | github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= 251 | github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= 252 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 253 | github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= 254 | github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= 255 | github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= 256 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 257 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 258 | github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= 259 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 260 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 261 | github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= 262 | github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= 263 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 264 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 265 | github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= 266 | github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= 267 | github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= 268 | github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= 269 | github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= 270 | github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= 271 | github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= 272 | github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= 273 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 274 | github.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204 h1:+EYBkW+dbi3F/atB+LSQZSWh7+HNrV3A/N0y6DSoy9k= 275 | github.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= 276 | github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= 277 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 278 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= 279 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 280 | github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= 281 | github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= 282 | github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= 283 | github.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk= 284 | github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= 285 | github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= 286 | github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= 287 | github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8= 288 | github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= 289 | github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= 290 | github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= 291 | github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= 292 | github.com/ipfs/go-cid v0.2.0 h1:01JTiihFq9en9Vz0lc0VDWvZe/uBonGpzo4THP0vcQ0= 293 | github.com/ipfs/go-cid v0.2.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro= 294 | github.com/ipfs/go-ipfs-api v0.3.0 h1:ZzVrsTV31Z53ZlUare6a5UJ46lC7lW93q/s1/fXyATk= 295 | github.com/ipfs/go-ipfs-api v0.3.0/go.mod h1:A1naQGm0Jg01GxDq7oDyVSZxt20SuRTNIBFNZJgPDmg= 296 | github.com/ipfs/go-ipfs-files v0.0.9/go.mod h1:aFv2uQ/qxWpL/6lidWvnSQmaVqCrf0TBGoUr+C1Fo84= 297 | github.com/ipfs/go-ipfs-files v0.1.1 h1:/MbEowmpLo9PJTEQk16m9rKzUHjeP4KRU9nWJyJO324= 298 | github.com/ipfs/go-ipfs-files v0.1.1/go.mod h1:8xkIrMWH+Y5P7HvJ4Yc5XWwIW2e52dyXUiC0tZyjDbM= 299 | github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= 300 | github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= 301 | github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= 302 | github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= 303 | github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= 304 | github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= 305 | github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 306 | github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 307 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 308 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 309 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 310 | github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= 311 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 312 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 313 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 314 | github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= 315 | github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= 316 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 317 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 318 | github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= 319 | github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= 320 | github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= 321 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 322 | github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 323 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 324 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 325 | github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= 326 | github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 327 | github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 328 | github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= 329 | github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A= 330 | github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= 331 | github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 332 | github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 333 | github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 334 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 335 | github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE= 336 | github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= 337 | github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= 338 | github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= 339 | github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= 340 | github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= 341 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 342 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 343 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 344 | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 345 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 346 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 347 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 348 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 349 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 350 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 351 | github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= 352 | github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= 353 | github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= 354 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 355 | github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= 356 | github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= 357 | github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= 358 | github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= 359 | github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= 360 | github.com/libp2p/go-libp2p-core v0.15.1 h1:0RY+Mi/ARK9DgG1g9xVQLb8dDaaU8tCePMtGALEfBnM= 361 | github.com/libp2p/go-libp2p-core v0.15.1/go.mod h1:agSaboYM4hzB1cWekgVReqV5M4g5M+2eNNejV+1EEhs= 362 | github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= 363 | github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= 364 | github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= 365 | github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= 366 | github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 367 | github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 368 | github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 369 | github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= 370 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 371 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 372 | github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 373 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 374 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 375 | github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= 376 | github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 377 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 378 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 379 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 380 | github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= 381 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 382 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= 383 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 384 | github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 385 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 386 | github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= 387 | github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= 388 | github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 389 | github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 390 | github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= 391 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 392 | github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= 393 | github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= 394 | github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= 395 | github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= 396 | github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= 397 | github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= 398 | github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= 399 | github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= 400 | github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= 401 | github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= 402 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 403 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 404 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 405 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 406 | github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= 407 | github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= 408 | github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 409 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 410 | github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= 411 | github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 412 | github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= 413 | github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= 414 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 415 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 416 | github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= 417 | github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= 418 | github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 419 | github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= 420 | github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 421 | github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= 422 | github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= 423 | github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE= 424 | github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM= 425 | github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= 426 | github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= 427 | github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= 428 | github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= 429 | github.com/multiformats/go-multiaddr v0.5.0 h1:i/JuOoVg4szYQ4YEzDGtb2h0o8M7CG/Yq6cGlcjWZpM= 430 | github.com/multiformats/go-multiaddr v0.5.0/go.mod h1:3KAxNkUqLTJ20AAwN4XVX4kZar+bR+gh4zgbfr3SNug= 431 | github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= 432 | github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= 433 | github.com/multiformats/go-multicodec v0.4.1 h1:BSJbf+zpghcZMZrwTYBGwy0CPcVZGWiC72Cp8bBd4R4= 434 | github.com/multiformats/go-multicodec v0.4.1/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= 435 | github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= 436 | github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= 437 | github.com/multiformats/go-multihash v0.1.0 h1:CgAgwqk3//SVEw3T+6DqI4mWMyRuDwZtOWcJT0q9+EA= 438 | github.com/multiformats/go-multihash v0.1.0/go.mod h1:RJlXsxt6vHGaia+S8We0ErjhojtKzPP2AH4+kYM7k84= 439 | github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= 440 | github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= 441 | github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= 442 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 443 | github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= 444 | github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= 445 | github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= 446 | github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc= 447 | github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= 448 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 449 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= 450 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 451 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 452 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 453 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 454 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 455 | github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= 456 | github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= 457 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 458 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 459 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 460 | github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 461 | github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 462 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 463 | github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 464 | github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= 465 | github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= 466 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 467 | github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= 468 | github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= 469 | github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= 470 | github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 471 | github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= 472 | github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= 473 | github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= 474 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 475 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 476 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 477 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 478 | github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= 479 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 480 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 481 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 482 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 483 | github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= 484 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 485 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 486 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 487 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 488 | github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 489 | github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 490 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 491 | github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= 492 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 493 | github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 494 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 495 | github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= 496 | github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= 497 | github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= 498 | github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 499 | github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= 500 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 501 | github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= 502 | github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8= 503 | github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= 504 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 505 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 506 | github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= 507 | github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= 508 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 509 | github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= 510 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= 511 | github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= 512 | github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= 513 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= 514 | github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= 515 | github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= 516 | github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= 517 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 518 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 519 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= 520 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 521 | github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= 522 | github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 523 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 524 | github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= 525 | github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= 526 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 527 | github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= 528 | github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 529 | github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= 530 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 531 | github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= 532 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 533 | github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 534 | github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= 535 | github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= 536 | github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= 537 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 538 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 539 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 540 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 541 | github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= 542 | github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= 543 | github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= 544 | github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= 545 | github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= 546 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 547 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 548 | github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 549 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 550 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 551 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 552 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 553 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 554 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 555 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 556 | github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= 557 | github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= 558 | github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= 559 | github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= 560 | github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= 561 | github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= 562 | github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= 563 | github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= 564 | github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= 565 | github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o= 566 | github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= 567 | github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 568 | github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= 569 | github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= 570 | github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 571 | github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 572 | github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= 573 | github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 574 | github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= 575 | github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= 576 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 577 | github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= 578 | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 579 | github.com/whyrusleeping/tar-utils v0.0.0-20180509141711-8c6c8ba81d5c/go.mod h1:xxcJeBb7SIUl/Wzkz1eVKJE/CB34YNrqX2TQI6jY9zs= 580 | github.com/whyrusleeping/tar-utils v0.0.0-20201201191210-20a61371de5b h1:wA3QeTsaAXybLL2kb2cKhCAQTHgYTMwuI8lBlJSv5V8= 581 | github.com/whyrusleeping/tar-utils v0.0.0-20201201191210-20a61371de5b/go.mod h1:xT1Y5p2JR2PfSZihE0s4mjdJaRGp1waCTf5JzhQLBck= 582 | github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= 583 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= 584 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= 585 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 586 | github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= 587 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 588 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 589 | github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= 590 | github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= 591 | go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= 592 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 593 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 594 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 595 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 596 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 597 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 598 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 599 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 600 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 601 | golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 602 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 603 | golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 604 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 605 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 606 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 607 | golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 608 | golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 609 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 610 | golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 611 | golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 612 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 613 | golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 614 | golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 615 | golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 616 | golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 617 | golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= 618 | golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 619 | golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 620 | golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 621 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 622 | golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 623 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 624 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 625 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 626 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 627 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 628 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 629 | golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= 630 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 631 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 632 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 633 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 634 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 635 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 636 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 637 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 638 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 639 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 640 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 641 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 642 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 643 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 644 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 645 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 646 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 647 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 648 | golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 649 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 650 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 651 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 652 | golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 653 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 654 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 655 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 656 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 657 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 658 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 659 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 660 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 661 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 662 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 663 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 664 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 665 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 666 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 667 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 668 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 669 | golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 670 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 671 | golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 672 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 673 | golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 674 | golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 675 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 676 | golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 677 | golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 678 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 679 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 680 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 681 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 682 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 683 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 684 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 685 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 686 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 687 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 688 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 689 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 690 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= 691 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 692 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 693 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 694 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 695 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 696 | golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 697 | golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 698 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 699 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 700 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 701 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 702 | golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 703 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 704 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 705 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 706 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 707 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 708 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 709 | golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 710 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 711 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 712 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 713 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 714 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 715 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 716 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 717 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 718 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 719 | golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 720 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 721 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 722 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 723 | golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 724 | golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 725 | golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 726 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 727 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 728 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 729 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 730 | golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 731 | golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 732 | golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 733 | golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 734 | golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 735 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 736 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 737 | golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 738 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 739 | golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 740 | golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc= 741 | golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 742 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 743 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 744 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 745 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 746 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 747 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 748 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 749 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 750 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 751 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 752 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 753 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 754 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 755 | golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 756 | golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= 757 | golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 758 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 759 | golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 760 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 761 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 762 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 763 | golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 764 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 765 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 766 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 767 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 768 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 769 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 770 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 771 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 772 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 773 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 774 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 775 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 776 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 777 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 778 | golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 779 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 780 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 781 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 782 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 783 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 784 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 785 | golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 786 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 787 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 788 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 789 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 790 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 791 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 792 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 793 | gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= 794 | gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= 795 | gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= 796 | gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= 797 | gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= 798 | gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= 799 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 800 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 801 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 802 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 803 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 804 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 805 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 806 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 807 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 808 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 809 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 810 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 811 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 812 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 813 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 814 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 815 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 816 | google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 817 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 818 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 819 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 820 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 821 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 822 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 823 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 824 | google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 825 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 826 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 827 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 828 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 829 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 830 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 831 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 832 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 833 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 834 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 835 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 836 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 837 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 838 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 839 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 840 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 841 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 842 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 843 | gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= 844 | gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 845 | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= 846 | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= 847 | gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= 848 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 849 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 850 | gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= 851 | gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= 852 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 853 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 854 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 855 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 856 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 857 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 858 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 859 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 860 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 861 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 862 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 863 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 864 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 865 | gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= 866 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 867 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 868 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 869 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 870 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 871 | honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= 872 | lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= 873 | lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= 874 | lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= 875 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 876 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 877 | -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nomasters/killcord/a11662b78e83ba02ff81fd9ecc550ebc886449ee/images/logo.png -------------------------------------------------------------------------------- /images/relational-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nomasters/killcord/a11662b78e83ba02ff81fd9ecc550ebc886449ee/images/relational-diagram.png -------------------------------------------------------------------------------- /killcord/cmd/checkin.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/nomasters/killcord" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var checkinCmd = &cobra.Command{ 12 | Use: "checkin", 13 | Short: "Checkin with current timestamp", 14 | Long: `The checkin command is used by the owner account to update the 15 | checking timestamp for a contract.`, 16 | Run: func(cmd *cobra.Command, args []string) { 17 | if cfgFileExists == false { 18 | fmt.Println("no killcord.toml found, run `killcord init` to start a new project") 19 | os.Exit(1) 20 | } 21 | config, err := getConfigFile() 22 | if err != nil { 23 | fmt.Println("something went wrong with reading the config file, exiting.") 24 | os.Exit(1) 25 | } 26 | opts := setOptionsFromEnv() 27 | 28 | session := killcord.New() 29 | session.Config = config 30 | session.Options = opts 31 | session.Init() 32 | 33 | if err := session.CheckIn(); err != nil { 34 | fmt.Println(err) 35 | os.Exit(1) 36 | } 37 | // write config to disk 38 | if err := updateConfigFile(session.Config); err != nil { 39 | fmt.Println(err) 40 | os.Exit(1) 41 | } 42 | }, 43 | } 44 | 45 | func init() { 46 | rootCmd.AddCommand(checkinCmd) 47 | } 48 | -------------------------------------------------------------------------------- /killcord/cmd/contract.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/nomasters/killcord" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var contractCmd = &cobra.Command{ 12 | Use: "contract", 13 | Short: "Manage a contract", 14 | Long: `More options will become available, but currently this command only 15 | accepts the --kill flag which is used to kill an existing contract`, 16 | Run: func(cmd *cobra.Command, args []string) { 17 | if cfgFileExists == false { 18 | fmt.Println("no killcord.toml found, run `killcord init` to start a new project") 19 | os.Exit(1) 20 | } 21 | config, err := getConfigFile() 22 | if err != nil { 23 | fmt.Println("something went wrong with reading the config file, exiting.") 24 | os.Exit(1) 25 | } 26 | kill, err := cmd.Flags().GetBool("kill") 27 | if err != nil { 28 | fmt.Println(err) 29 | os.Exit(1) 30 | } 31 | 32 | session := killcord.New() 33 | session.Config = config 34 | session.Options = setOptionsFromEnv() 35 | session.Init() 36 | 37 | if kill == true { 38 | if err := session.KillContract(); err != nil { 39 | fmt.Println(err) 40 | os.Exit(1) 41 | } 42 | } 43 | // write config to disk 44 | if err := updateConfigFile(session.Config); err != nil { 45 | fmt.Println(err) 46 | os.Exit(1) 47 | } 48 | }, 49 | } 50 | 51 | var deployContractCmd = &cobra.Command{ 52 | Use: "deploy", 53 | Short: "Deploy a contract", 54 | Long: `This command deploys a smart contract and writes all the configuration 55 | details to the config file. Deploying a contract requires that the owner account 56 | has enough currency provided to fund the the deployment of a contract.`, 57 | Run: func(cmd *cobra.Command, args []string) { 58 | // Ensure no configuration file exists. 59 | // If one does, exit with message. 60 | if cfgFileExists == false { 61 | fmt.Println("no killcord.toml found, run `killcord init` to start a new project") 62 | os.Exit(1) 63 | } 64 | // Set default status options for a public killcord. 65 | opts := setOptionsFromEnv() 66 | config, err := getConfigFile() 67 | if err != nil { 68 | fmt.Println("something went wrong with reading the config file, exiting.") 69 | os.Exit(1) 70 | } 71 | 72 | session := killcord.New() 73 | session.Options = opts 74 | session.Config = config 75 | session.Init() 76 | if err := session.DeployContract(); err != nil { 77 | fmt.Println(err) 78 | os.Exit(1) 79 | } 80 | // write config to disk 81 | if err := updateConfigFile(session.Config); err != nil { 82 | fmt.Println(err) 83 | os.Exit(1) 84 | } 85 | }, 86 | } 87 | 88 | func init() { 89 | contractCmd.Flags().BoolP("kill", "k", false, "kill contract") 90 | rootCmd.AddCommand(contractCmd) 91 | contractCmd.AddCommand(deployContractCmd) 92 | } 93 | -------------------------------------------------------------------------------- /killcord/cmd/decrypt.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/nomasters/killcord" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var decryptCmd = &cobra.Command{ 12 | Use: "decrypt", 13 | Short: "Decrypts a payload", 14 | Long: `The decrypt command uses the settings stored in the configuration file to decrypt 15 | a payload stored in the payload/encrypted directory.`, 16 | Run: func(cmd *cobra.Command, args []string) { 17 | if cfgFileExists == false { 18 | fmt.Println("no killcord.toml found, run `killcord init` to start a new project") 19 | os.Exit(1) 20 | } 21 | config, err := getConfigFile() 22 | if err != nil { 23 | fmt.Println("something went wrong with reading the config file, exiting.") 24 | os.Exit(1) 25 | } 26 | 27 | session := killcord.New() 28 | session.Config = config 29 | session.Init() 30 | 31 | if err := session.Decrypt(); err != nil { 32 | fmt.Println(err) 33 | os.Exit(1) 34 | } 35 | // write config to disk 36 | if err := updateConfigFile(session.Config); err != nil { 37 | fmt.Println(err) 38 | os.Exit(1) 39 | } 40 | }, 41 | } 42 | 43 | func init() { 44 | rootCmd.AddCommand(decryptCmd) 45 | } 46 | -------------------------------------------------------------------------------- /killcord/cmd/encrypt.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/nomasters/killcord" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var encryptCmd = &cobra.Command{ 12 | Use: "encrypt", 13 | Short: "Encrypts a payload", 14 | Long: `The encrypt command uses the settings stored in the configuration file to encrypt 15 | a payload stored in the payload/source directory.`, 16 | Run: func(cmd *cobra.Command, args []string) { 17 | if cfgFileExists == false { 18 | fmt.Println("no killcord.toml found, run `killcord init` to start a new project") 19 | os.Exit(1) 20 | } 21 | config, err := getConfigFile() 22 | if err != nil { 23 | fmt.Println("something went wrong with reading the config file, exiting.") 24 | os.Exit(1) 25 | } 26 | session := killcord.New() 27 | session.Config = config 28 | session.Init() 29 | 30 | if err := session.Encrypt(); err != nil { 31 | fmt.Println(err) 32 | os.Exit(1) 33 | } 34 | // write config to disk 35 | if err := updateConfigFile(session.Config); err != nil { 36 | fmt.Println(err) 37 | os.Exit(1) 38 | } 39 | }, 40 | } 41 | 42 | func init() { 43 | rootCmd.AddCommand(encryptCmd) 44 | } 45 | -------------------------------------------------------------------------------- /killcord/cmd/init.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/nomasters/killcord" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var initCmd = &cobra.Command{ 12 | Use: "init", 13 | Short: "Initializes a killcord project", 14 | Long: ` 15 | The killcord init command creates the project folder structure required 16 | to own a killcord project. If you plan on releasing a payload to the 17 | public in the event of death or disappearance, start here.`, 18 | Run: func(cmd *cobra.Command, args []string) { 19 | // Ensure no configuration file exists. 20 | // If one does, exit with message. 21 | if cfgFileExists == true { 22 | fmt.Println("killcord.toml discovered, killcord is already initialized") 23 | os.Exit(1) 24 | } 25 | 26 | // Set default options for a public killcord. This is a structural placeholder 27 | // for future features in which Payload and Contract Providers can be switched 28 | // out independently. 29 | opts := setOptionsFromEnv() 30 | opts.Type = "owner" 31 | opts.Audience = "public" 32 | opts.Payload.Provider = "ipfs" 33 | opts.Contract.Provider = "ethereum" 34 | 35 | session := killcord.New() 36 | session.Options = opts 37 | session.Init() 38 | 39 | // Start a new project with the options provided and return ProjectConfig 40 | if err := session.NewProject(); err != nil { 41 | fmt.Println(err) 42 | os.Exit(1) 43 | } 44 | 45 | // write config to disk 46 | if err := updateConfigFile(session.Config); err != nil { 47 | fmt.Println(err) 48 | os.Exit(1) 49 | } 50 | }, 51 | } 52 | 53 | func init() { 54 | rootCmd.AddCommand(initCmd) 55 | initCmd.Flags().BoolVar(&devMode, "dev", false, "initialize project to run in dev mode") 56 | } 57 | -------------------------------------------------------------------------------- /killcord/cmd/payload.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/nomasters/killcord" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var payloadCmd = &cobra.Command{ 12 | Use: "payload", 13 | Short: "Manage the payload", 14 | Long: `This is a placeholder for future work. To use the payload command 15 | you will need to run "killcord payload deploy"`, 16 | Run: func(cmd *cobra.Command, args []string) { 17 | }, 18 | } 19 | 20 | var payloadDeploy = &cobra.Command{ 21 | Use: "deploy", 22 | Short: "Deploy a payload to a storage endpoint", 23 | Long: `Payload deploy deploys a payload to a storage endpoint and 24 | registers that enpoint to the smart contract.`, 25 | Run: func(cmd *cobra.Command, args []string) { 26 | if cfgFileExists == false { 27 | fmt.Println("no killcord.toml found, run `killcord init` to start a new project") 28 | os.Exit(1) 29 | } 30 | 31 | config, err := getConfigFile() 32 | if err != nil { 33 | fmt.Println("something went wrong with reading the config file, exiting.") 34 | os.Exit(1) 35 | } 36 | 37 | opts := setOptionsFromEnv() 38 | 39 | session := killcord.New() 40 | session.Config = config 41 | session.Options = opts 42 | session.Init() 43 | 44 | if err := session.DeployPayload(); err != nil { 45 | fmt.Println(err) 46 | os.Exit(1) 47 | } 48 | // write config to disk 49 | if err := updateConfigFile(session.Config); err != nil { 50 | fmt.Println(err) 51 | os.Exit(1) 52 | } 53 | }, 54 | } 55 | 56 | func init() { 57 | payloadCmd.AddCommand(payloadDeploy) 58 | rootCmd.AddCommand(payloadCmd) 59 | } 60 | -------------------------------------------------------------------------------- /killcord/cmd/publish.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/nomasters/killcord" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var publishCmd = &cobra.Command{ 12 | Use: "publish", 13 | Short: "Publishes the decryption key to the contract", 14 | Long: `Publishes the decryption key to the contract`, 15 | Run: func(cmd *cobra.Command, args []string) { 16 | if cfgFileExists == false { 17 | fmt.Println("no killcord.toml found, run `killcord init` to start a new project") 18 | os.Exit(1) 19 | } 20 | config, err := getConfigFile() 21 | if err != nil { 22 | fmt.Println("something went wrong with reading the config file, exiting.") 23 | os.Exit(1) 24 | } 25 | 26 | session := killcord.New() 27 | session.Config = config 28 | session.Options = setOptionsFromEnv() 29 | session.Init() 30 | 31 | if err := session.PublishKey(); err != nil { 32 | fmt.Println(err) 33 | os.Exit(1) 34 | } 35 | // write config to disk 36 | if err := updateConfigFile(session.Config); err != nil { 37 | fmt.Println(err) 38 | os.Exit(1) 39 | } 40 | }, 41 | } 42 | 43 | func init() { 44 | rootCmd.AddCommand(publishCmd) 45 | } 46 | -------------------------------------------------------------------------------- /killcord/cmd/publisher.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/nomasters/killcord" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var publisherCmd = &cobra.Command{ 12 | Use: "publisher", 13 | Short: "Manage the Publisher", 14 | Long: `This Command is a placeholder for future publisher commands. 15 | Currently the only publisher command is "killcord publisher run".`, 16 | Run: func(cmd *cobra.Command, args []string) { 17 | }, 18 | } 19 | 20 | var runPublisherCmd = &cobra.Command{ 21 | Use: "run", 22 | Short: "Runs the Publisher threshold check.", 23 | Long: `Publisher Run is the primary interface for automating the publisher 24 | threshold check. This command is configured to use either a config file or 25 | ENV settings to read a smart contract's lastCheckin value and evaluate it against 26 | the publisher threshold. If the threshold exceeded, the command automatically 27 | publishes the secret to the smart contract. If the secret is already published, 28 | this step is skipped.`, 29 | Run: func(cmd *cobra.Command, args []string) { 30 | 31 | // get config and opts 32 | config, _ := getConfigFile() // if no config file is Found this is fine 33 | opts := setOptionsFromEnv() 34 | 35 | session := killcord.New() 36 | session.Options = opts 37 | session.Config = config 38 | session.Init() 39 | 40 | if err := session.RunPublisher(); err != nil { 41 | fmt.Println(err) 42 | os.Exit(1) 43 | } 44 | }, 45 | } 46 | 47 | func init() { 48 | rootCmd.AddCommand(publisherCmd) 49 | publisherCmd.AddCommand(runPublisherCmd) 50 | runPublisherCmd.Flags().BoolVar(&devMode, "dev", false, "run in dev mode") 51 | } 52 | -------------------------------------------------------------------------------- /killcord/cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/BurntSushi/toml" 9 | "github.com/nomasters/killcord" 10 | "github.com/spf13/cobra" 11 | "github.com/spf13/viper" 12 | ) 13 | 14 | var cfgFile string 15 | var cfgFileExists bool 16 | var devMode bool 17 | 18 | var rootCmd = &cobra.Command{ 19 | Use: "killcord", 20 | Short: "A censorship resistant dead man's switch", 21 | Long: `killcord is designed for a project owner to be able to automatically release 22 | a decryption key in the circumstance that the owner stops checking-in after a predefined 23 | window of time. This allows an owner to release a secret data dump to the public in the 24 | event of death or disappearance.`, 25 | } 26 | 27 | func Execute() { 28 | if err := rootCmd.Execute(); err != nil { 29 | fmt.Println(err) 30 | os.Exit(1) 31 | } 32 | } 33 | 34 | func init() { 35 | cobra.OnInitialize(initConfig) 36 | 37 | // Here you will define your flags and configuration settings. 38 | // Cobra supports persistent flags, which, if defined here, 39 | // will be global for your application. 40 | //rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is ./killcord.toml)") 41 | 42 | // Cobra also supports local flags, which will only run 43 | // when this action is called directly. 44 | rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") 45 | } 46 | 47 | // initConfig reads in config file and ENV variables if set. 48 | func initConfig() { 49 | if cfgFile != "" { 50 | viper.SetConfigFile(cfgFile) 51 | } else { 52 | // get the configuration file from the current directory 53 | viper.AddConfigPath(".") 54 | viper.SetConfigName("killcord") 55 | } 56 | 57 | // support ENV for killcord settings 58 | viper.SetEnvPrefix("killcord") 59 | viper.BindEnv("payload.secret", "KILLCORD_PAYLOAD_SECRET") 60 | viper.BindEnv("contract.id", "KILLCORD_CONTRACT_ID") 61 | viper.BindEnv("contract.publisher.address", "KILLCORD_CONTRACT_PUBLISHER_ADDRESS") 62 | viper.BindEnv("contract.publisher.password", "KILLCORD_CONTRACT_PUBLISHER_PASSWORD") 63 | viper.BindEnv("contract.publisher.keystore", "KILLCORD_CONTRACT_PUBLISHER_KEYSTORE") 64 | viper.BindEnv("contract.rpcUrl", "KILLCORD_CONTRACT_RPCURL") 65 | viper.BindEnv("payload.rpcUrl", "KILLCORD_PAYLOAD_RPCURL") 66 | viper.BindEnv("publisher.warningThreshold", "KILLCORD_PUBLISHER_WARNING_THRESHOLD") 67 | viper.BindEnv("publisher.publishThreshold", "KILLCORD_PUBLISHER_PUBLISH_THRESHOLD") 68 | viper.AutomaticEnv() // read in environment variables that match 69 | 70 | // If a config file is found, read it in. 71 | if err := viper.ReadInConfig(); err == nil { 72 | cfgFileExists = true 73 | } 74 | } 75 | 76 | func setOptionsFromEnv() killcord.ProjectOptions { 77 | opts := killcord.ProjectOptions{} 78 | opts.DevMode = devMode 79 | if x, ok := viper.Get("payload.id").(string); ok { 80 | opts.Payload.ID = x 81 | } 82 | if x, ok := viper.Get("payload.secret").(string); ok { 83 | opts.Payload.Secret = x 84 | } 85 | if x, ok := viper.Get("publisher.warningThreshold").(int64); ok { 86 | opts.Publisher.WarningThreshold = x 87 | } 88 | if x, ok := viper.Get("publisher.publishThreshold").(int64); ok { 89 | opts.Publisher.PublishThreshold = x 90 | } 91 | if x, ok := viper.Get("contract.id").(string); ok { 92 | opts.Contract.ID = x 93 | } 94 | if x, ok := viper.Get("contract.publisher.address").(string); ok { 95 | opts.Contract.Publisher.Address = x 96 | } 97 | if x, ok := viper.Get("contract.publisher.password").(string); ok { 98 | opts.Contract.Publisher.Password = x 99 | } 100 | if x, ok := viper.Get("contract.publisher.keystore").(string); ok { 101 | opts.Contract.Publisher.KeyStore = x 102 | } 103 | if x, ok := viper.Get("contract.rpcUrl").(string); ok { 104 | opts.Contract.RPCURL = x 105 | } 106 | if x, ok := viper.Get("payload.rpcUrl").(string); ok { 107 | opts.Payload.RPCURL = x 108 | } 109 | return opts 110 | } 111 | 112 | func getConfigFile() (killcord.ProjectConfig, error) { 113 | var config killcord.ProjectConfig 114 | if _, err := toml.DecodeFile("killcord.toml", &config); err != nil { 115 | return config, err 116 | } 117 | return config, nil 118 | } 119 | 120 | func updateConfigFile(config killcord.ProjectConfig) error { 121 | fo, err := os.OpenFile("killcord.toml", os.O_RDWR|os.O_CREATE, 0755) 122 | if err != nil { 123 | return err 124 | } 125 | defer func() { 126 | if err := fo.Close(); err != nil { 127 | panic(err) 128 | } 129 | }() 130 | w := bufio.NewWriter(fo) 131 | c := toml.NewEncoder(w) 132 | if err := c.Encode(&config); err != nil { 133 | return err 134 | } 135 | if err := viper.ReadInConfig(); err == nil { 136 | cfgFileExists = true 137 | } else { 138 | return err 139 | } 140 | return nil 141 | } 142 | -------------------------------------------------------------------------------- /killcord/cmd/status.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/nomasters/killcord" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var statusCmd = &cobra.Command{ 12 | Use: "status", 13 | Short: "Check the status of the project", 14 | Long: ` 15 | Status is used to check important status information about 16 | an existing project.`, 17 | Run: func(cmd *cobra.Command, args []string) { 18 | // Ensure no configuration file exists. 19 | // If one does, exit with message. 20 | if cfgFileExists == false { 21 | fmt.Println("no killcord.toml found, run `killcord init` to start a new project") 22 | os.Exit(1) 23 | } 24 | 25 | config, err := getConfigFile() 26 | if err != nil { 27 | fmt.Println("something went wrong with reading the config file, exiting.") 28 | os.Exit(1) 29 | } 30 | opts := setOptionsFromEnv() 31 | 32 | session := killcord.New() 33 | session.Config = config 34 | session.Options = opts 35 | session.Init() 36 | 37 | if err := session.GetStatus(); err != nil { 38 | fmt.Println(err) 39 | os.Exit(1) 40 | } 41 | 42 | // write config to disk 43 | if err := updateConfigFile(session.Config); err != nil { 44 | fmt.Println(err) 45 | os.Exit(1) 46 | } 47 | }, 48 | } 49 | 50 | func init() { 51 | rootCmd.AddCommand(statusCmd) 52 | } 53 | -------------------------------------------------------------------------------- /killcord/cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/nomasters/killcord" 7 | "github.com/spf13/cobra" 8 | ) 9 | 10 | var versionCmd = &cobra.Command{ 11 | Use: "version", 12 | Short: "Prints the killcord version", 13 | Long: `Prints the killcord version`, 14 | Run: func(cmd *cobra.Command, args []string) { 15 | fmt.Println(killcord.Version) 16 | }, 17 | } 18 | 19 | func init() { 20 | rootCmd.AddCommand(versionCmd) 21 | } 22 | -------------------------------------------------------------------------------- /killcord/cmd/watch.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/nomasters/killcord" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var watchCmd = &cobra.Command{ 12 | Use: "watch", 13 | Short: "Initializes a watcher project", 14 | Long: `The watch command is used to initialize a project to watch an existing project. 15 | The watcher downloads the payload and can run the status and decrypt commands on a payload.`, 16 | Run: func(cmd *cobra.Command, args []string) { 17 | // Ensure no configuration file exists. 18 | // If one does, exit with message. 19 | if cfgFileExists == true { 20 | fmt.Println("killcord.toml discovered, killcord is already initialized") 21 | os.Exit(1) 22 | } 23 | 24 | // Set default options for a killcord watcher project. This is a structural placeholder 25 | // for future features in which Payload and Contract Providers can be switched 26 | // out independently. 27 | 28 | session := killcord.New() 29 | opts := setOptionsFromEnv() 30 | opts.Type = "watcher" 31 | opts.Payload.Provider = "ipfs" 32 | opts.Contract.Provider = "ethereum" 33 | opts.Contract.ID = args[0] 34 | session.Options = opts 35 | session.Init() 36 | if err := session.NewProject(); err != nil { 37 | fmt.Println(err) 38 | os.Exit(1) 39 | } 40 | 41 | // write config to disk 42 | if err := updateConfigFile(session.Config); err != nil { 43 | fmt.Println(err) 44 | os.Exit(1) 45 | } 46 | }, 47 | } 48 | 49 | func init() { 50 | rootCmd.AddCommand(watchCmd) 51 | watchCmd.Flags().BoolVar(&devMode, "dev", false, "run in dev mode") 52 | } 53 | -------------------------------------------------------------------------------- /killcord/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/nomasters/killcord/killcord/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /payload.go: -------------------------------------------------------------------------------- 1 | package killcord 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/hex" 6 | "errors" 7 | "fmt" 8 | "io" 9 | "log" 10 | "os" 11 | "path/filepath" 12 | "strings" 13 | 14 | "github.com/cheggaaa/pb/v3" 15 | shell "github.com/ipfs/go-ipfs-api" 16 | archiver "github.com/mholt/archiver/v3" 17 | "golang.org/x/crypto/nacl/secretbox" 18 | ) 19 | 20 | const ( 21 | maxChunkSize = 16000 22 | sourcePrefix = "payload/source" 23 | encryptPrefix = "payload/encrypted" 24 | decryptPrefix = "payload/decrypted" 25 | tempPrefix = "payload/tmp" 26 | maxChunksCache = 900000 27 | maxReadSize = 900000 28 | defaultpayloadRPCPath = "https://ipfs.infura.io:5001" 29 | defaultOutputZipName = "output.zip" 30 | defaultOutputKilName = "output.kil" 31 | ) 32 | 33 | var ( 34 | payloadSourcePath string 35 | payloadEncryptedPath string 36 | payloadTempPath string 37 | payloadDecryptPath string 38 | payloadRPCPath string = defaultpayloadRPCPath 39 | ) 40 | 41 | func init() { 42 | payloadSourcePath = filepath.Join(strings.Split(sourcePrefix, "/")...) 43 | payloadEncryptedPath = filepath.Join(strings.Split(encryptPrefix, "/")...) 44 | payloadTempPath = filepath.Join(strings.Split(tempPrefix, "/")...) 45 | payloadDecryptPath = filepath.Join(strings.Split(decryptPrefix, "/")...) 46 | } 47 | 48 | // Chunk is a byte slice used for chunking data 49 | type Chunk []byte 50 | 51 | // getShellURL waterfalls settings and returns the RPC url in priority 52 | // order from Options, Config, or Default settings 53 | 54 | func (s *Session) setPayloadRPCPath() { 55 | if s.Options.Payload.RPCURL != "" { 56 | payloadRPCPath = s.Options.Payload.RPCURL 57 | return 58 | } 59 | if s.Config.Payload.RPCURL != "" { 60 | payloadRPCPath = s.Config.Payload.RPCURL 61 | return 62 | } 63 | payloadRPCPath = defaultpayloadRPCPath 64 | } 65 | 66 | // DeployPayload takes the contents from the /payload/encrypted and adds it to 67 | // the storage endpoint 68 | func (s *Session) DeployPayload() error { 69 | // check that encrypted payload exists, exit if it doesn't 70 | if _, err := os.Stat(filepath.Join(payloadEncryptedPath, defaultOutputKilName)); os.IsNotExist(err) { 71 | return errors.New("encrypted payload does not exist, exiting") 72 | } 73 | // check for payload ID in config, exti if it already exists 74 | if s.Config.Payload.ID != "" { 75 | return fmt.Errorf("payload %v already deployed, skipping", s.Config.Payload.ID) 76 | } 77 | sh := shell.NewShell(payloadRPCPath) 78 | f, err := os.Open(filepath.Join(payloadEncryptedPath, defaultOutputKilName)) 79 | if err != nil { 80 | return err 81 | } 82 | mhash, err := sh.Add(f) 83 | if err != nil { 84 | return err 85 | } 86 | s.Config.Payload.ID = mhash 87 | if err := SetPayloadEndpoint(s.Config.Contract.Owner, s.Config.Contract.ID, s.Config.Payload.ID); err != nil { 88 | return err 89 | } 90 | s.Config.Payload.Status = "deployed" 91 | return nil 92 | } 93 | 94 | // GetPayload Gets the payload from the storage endpoint and stores it locally 95 | // in the Encrypted payload folder 96 | func (s *Session) GetPayload() error { 97 | sh := shell.NewShell(payloadRPCPath) 98 | if err := sh.Get(s.Config.Payload.ID, payloadEncryptedPath); err != nil { 99 | return err 100 | } 101 | s.Config.Payload.Status = "synced" 102 | if err := os.Rename(filepath.Join(payloadEncryptedPath, s.Config.Payload.ID), filepath.Join(payloadEncryptedPath, defaultOutputKilName)); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // Encrypt encrypts the payload 109 | func (s *Session) Encrypt() error { 110 | var key [32]byte 111 | os.RemoveAll(payloadTempPath) 112 | if err := os.Mkdir(payloadTempPath, 0755); err != nil { 113 | return err 114 | } 115 | if err := zipSource(); err != nil { 116 | return err 117 | } 118 | if err := s.setPayloadKey(); err != nil { 119 | return err 120 | } 121 | secret, err := hex.DecodeString(s.Config.Payload.Secret) 122 | if err != nil { 123 | return err 124 | } 125 | copy(key[:], secret) 126 | encryptMultiPart(key) 127 | os.RemoveAll(payloadTempPath) 128 | s.Config.Payload.Status = "encrypted" 129 | 130 | return nil 131 | } 132 | 133 | // Decrypt descrypts the payload and returns an error 134 | func (s *Session) Decrypt() error { 135 | var key [32]byte 136 | secret, err := hex.DecodeString(s.Config.Payload.Secret) 137 | if err != nil { 138 | return err 139 | } 140 | copy(key[:], secret) 141 | os.RemoveAll(payloadTempPath) 142 | os.Mkdir(payloadTempPath, 0755) 143 | decryptMultiPart(key) 144 | if err := unzipSource(); err != nil { 145 | return err 146 | } 147 | os.RemoveAll(payloadDecryptPath) 148 | if err := os.Rename(filepath.Join(payloadTempPath, "source"), payloadDecryptPath); err != nil { 149 | return err 150 | } 151 | os.RemoveAll(payloadTempPath) 152 | return nil 153 | } 154 | 155 | func getFileSize(path string) (int64, error) { 156 | info, err := os.Stat(path) 157 | if err != nil { 158 | return 0, err 159 | } 160 | return info.Size(), nil 161 | } 162 | 163 | func zipSource() error { 164 | fmt.Println("-- compressing payload (this could take a while) --") 165 | zip := filepath.Join(payloadTempPath, defaultOutputZipName) 166 | z := archiver.NewZip() 167 | if err := z.Archive([]string{payloadSourcePath}, zip); err != nil { 168 | return err 169 | } 170 | return nil 171 | } 172 | 173 | func unzipSource() error { 174 | fmt.Println("-- uncompressing payload (this could take a while) --") 175 | zip := filepath.Join(payloadTempPath, defaultOutputZipName) 176 | z := archiver.NewZip() 177 | if err := z.Unarchive(zip, payloadTempPath); err != nil { 178 | return err 179 | } 180 | return nil 181 | } 182 | 183 | func (s *Session) setPayloadKey() error { 184 | if s.Config.Payload.Secret != "" { 185 | return errors.New("encryption secret already set") 186 | } 187 | s.Config.Payload.Secret = generateKey() 188 | return nil 189 | } 190 | 191 | func initFile(file string) *os.File { 192 | i, err := os.Create(file) 193 | if err != nil { 194 | log.Fatal(err) 195 | } 196 | i.Close() 197 | f, err := os.OpenFile(file, os.O_APPEND|os.O_WRONLY, 0644) 198 | if err != nil { 199 | log.Fatal(err) 200 | } 201 | return f 202 | } 203 | 204 | func encryptMultiPart(k [32]byte) { 205 | s := filepath.Join(payloadTempPath, defaultOutputZipName) 206 | d := filepath.Join(payloadEncryptedPath, defaultOutputKilName) 207 | totalSize, _ := getFileSize(d) 208 | f := initFile(d) 209 | r := make(chan Chunk) 210 | w := make(chan Chunk) 211 | go reader(s, r) 212 | go encrypter(r, w, k, totalSize) 213 | writer(w, f) 214 | } 215 | 216 | func decryptMultiPart(k [32]byte) { 217 | s := filepath.Join(payloadEncryptedPath, defaultOutputKilName) 218 | d := filepath.Join(payloadTempPath, defaultOutputZipName) 219 | totalSize, _ := getFileSize(s) 220 | f := initFile(d) 221 | r := make(chan Chunk) 222 | w := make(chan Chunk) 223 | go reader(s, r) 224 | go decrypter(r, w, k, totalSize) 225 | writer(w, f) 226 | } 227 | 228 | func encrypter(r, w chan Chunk, k [32]byte, totalSize int64) { 229 | var block []byte 230 | count := int((totalSize / maxChunkSize) + 1) 231 | fmt.Println("-- encrypting payload --") 232 | bar := pb.StartNew(count) 233 | for { 234 | x, ok := <-r 235 | if len(r) == 0 { 236 | if !ok { 237 | break 238 | } 239 | } 240 | for _, b := range x { 241 | if len(block) < maxChunkSize { 242 | block = append(block, b) 243 | } 244 | if len(block) == maxChunkSize { 245 | e := encrypt(block, k) 246 | bar.Increment() 247 | w <- e 248 | block = []byte{} 249 | } 250 | } 251 | } 252 | e := encrypt(block, k) 253 | w <- e 254 | bar.Set(nil, count) 255 | bar.Finish() 256 | close(w) 257 | } 258 | 259 | func decrypter(r, w chan Chunk, k [32]byte, totalSize int64) { 260 | var block []byte 261 | var chunkSize = maxChunkSize + 40 262 | count := int((totalSize / maxChunkSize) + 1) 263 | fmt.Println("-- decrypting payload --") 264 | bar := pb.StartNew(count) 265 | for { 266 | x, ok := <-r 267 | if len(r) == 0 { 268 | if !ok { 269 | break 270 | } 271 | } 272 | for _, b := range x { 273 | if len(block) < chunkSize { 274 | block = append(block, b) 275 | } 276 | if len(block) == chunkSize { 277 | e := decrypt(block, k) 278 | bar.Increment() 279 | w <- e 280 | block = []byte{} 281 | } 282 | } 283 | } 284 | e := decrypt(block, k) 285 | w <- e 286 | bar.Set(nil, count) 287 | bar.Finish() 288 | close(w) 289 | } 290 | 291 | func reader(file string, r chan Chunk) { 292 | f, err := os.Open(file) 293 | if err != nil { 294 | log.Fatal(err) 295 | } 296 | fi, err := f.Stat() 297 | if err != nil { 298 | log.Fatal(err) 299 | } 300 | remaining := fi.Size() 301 | var offset int64 302 | 303 | for { 304 | if len(r) == 0 { 305 | if remaining <= maxReadSize { 306 | rc := make([]byte, remaining) 307 | f.ReadAt(rc, offset) 308 | r <- rc 309 | f.Close() 310 | close(r) 311 | return 312 | } else { 313 | rc := make([]byte, maxReadSize) 314 | f.ReadAt(rc, offset) 315 | r <- rc 316 | remaining = remaining - maxReadSize 317 | offset = offset + maxReadSize 318 | } 319 | } 320 | } 321 | 322 | } 323 | 324 | func writer(w chan Chunk, f *os.File) { 325 | var writeCache []byte 326 | for { 327 | x, ok := <-w 328 | if len(w) == 0 { 329 | if !ok { 330 | writeToFile(writeCache, f) 331 | f.Close() 332 | return 333 | } 334 | } 335 | for _, b := range x { 336 | if len(writeCache) < maxChunksCache { 337 | writeCache = append(writeCache, b) 338 | } 339 | if len(writeCache) == maxChunksCache { 340 | writeToFile(writeCache, f) 341 | writeCache = []byte{} 342 | } 343 | } 344 | } 345 | } 346 | 347 | func writeToFile(data []byte, f *os.File) { 348 | if _, err := f.Write(data); err != nil { 349 | log.Fatal(err) 350 | } 351 | } 352 | 353 | func encrypt(data []byte, key [32]byte) []byte { 354 | var nonce [24]byte 355 | if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil { 356 | panic(err) 357 | } 358 | return secretbox.Seal(nonce[:], data, &nonce, &key) 359 | } 360 | 361 | func decrypt(data []byte, key [32]byte) []byte { 362 | var nonce [24]byte 363 | copy(nonce[:], data[:24]) 364 | d, ok := secretbox.Open(nil, data[24:], &nonce, &key) 365 | if !ok { 366 | panic("decryption error") 367 | } 368 | return d 369 | } 370 | -------------------------------------------------------------------------------- /payload_test.go: -------------------------------------------------------------------------------- 1 | package killcord 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestSetPayloadRPCPath(t *testing.T) { 8 | s := New() 9 | s.setPayloadRPCPath() 10 | if payloadRPCPath != defaultpayloadRPCPath { 11 | t.Fail() 12 | } 13 | s.Config.Payload.RPCURL = "t1" 14 | s.setPayloadRPCPath() 15 | if payloadRPCPath != "t1" { 16 | t.Fail() 17 | } 18 | s.Options.Payload.RPCURL = "t2" 19 | s.setPayloadRPCPath() 20 | if payloadRPCPath != "t2" { 21 | t.Fail() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /project.go: -------------------------------------------------------------------------------- 1 | //go:generate ./scripts/contract-gen.sh 2 | 3 | package killcord 4 | 5 | import ( 6 | "crypto/rand" 7 | "encoding/hex" 8 | "errors" 9 | "fmt" 10 | "os" 11 | "path/filepath" 12 | "strings" 13 | "time" 14 | ) 15 | 16 | const ( 17 | Version = "0.0.1-alpha" 18 | defaultContractProvider = "ethereum" 19 | defaultPayloadProvider = "ipfs" 20 | ) 21 | 22 | var ProjectPath string 23 | 24 | type Session struct { 25 | Config ProjectConfig 26 | Options ProjectOptions 27 | } 28 | 29 | type ProjectOptions struct { 30 | DevMode bool 31 | Type string 32 | Audience string 33 | Version string 34 | Status StatusOptions 35 | Payload PayloadOptions 36 | Contract ContractOptions 37 | Publisher PublisherOptions 38 | } 39 | 40 | type StatusOptions struct { 41 | ViewAll bool 42 | } 43 | 44 | type PayloadOptions struct { 45 | SourcePath string 46 | DestinationPath string 47 | RPCURL string 48 | Provider string 49 | Secret string 50 | ID string 51 | } 52 | 53 | type ContractOptions struct { 54 | Kill bool 55 | Provider string 56 | ID string 57 | RPCURL string 58 | Owner AccountConfig 59 | Publisher AccountConfig 60 | } 61 | 62 | type PublisherOptions struct { 63 | WarningThreshold int64 64 | PublishThreshold int64 65 | Address string 66 | Password string 67 | KeyStore string 68 | } 69 | 70 | type ProjectConfig struct { 71 | Type string `toml:"type"` 72 | Version string `toml:"version"` 73 | Audience string `toml:"audience"` 74 | Created time.Time `toml:"created"` 75 | Updated time.Time `toml:"updated"` 76 | DevMode bool `toml:"devMode"` 77 | Payload PayloadConfig `toml:"payload"` 78 | Contract ContractConfig `toml:"contract"` 79 | Publisher PublisherConfig `toml:"publisher"` 80 | Status string `toml:"status"` 81 | } 82 | 83 | type PayloadConfig struct { 84 | Status string `toml:"status"` 85 | Provider string `toml:"provider"` 86 | ID string `toml:"id"` 87 | Secret string `toml:"secret"` 88 | Mode string `toml:"mode"` 89 | RPCURL string `toml:"rpcUrl"` 90 | } 91 | 92 | type ContractConfig struct { 93 | Status string `toml:"status"` 94 | Provider string `toml:"provider"` 95 | ID string `toml:"id"` 96 | Owner AccountConfig `toml:"owner"` 97 | Publisher AccountConfig `toml:"publisher"` 98 | Mode string `toml:"mode"` 99 | RPCURL string `toml:"rpcUrl"` 100 | } 101 | 102 | type AccountConfig struct { 103 | Address string `toml:"address"` 104 | Password string `toml:"password"` 105 | KeyStore string `toml:"keystore"` 106 | } 107 | 108 | type PublisherConfig struct { 109 | Status string `toml:"status"` 110 | WarningThreshold int64 `toml:"warningThreshold"` 111 | PublishThreshold int64 `toml:"publishThreshold"` 112 | } 113 | 114 | func init() { 115 | setAbsPath() 116 | } 117 | 118 | // Returns a new Killcord Session with defaults 119 | func New() *Session { 120 | return &Session{} 121 | } 122 | 123 | // initializes ProjectConfig and ProjectOptions session variables 124 | // for use by functions that use Payload and Contract RPC settings 125 | func (s *Session) Init() { 126 | s.setEthereumRPCPath() 127 | s.setPayloadRPCPath() 128 | } 129 | 130 | func (s *Session) NewProject() error { 131 | if err := s.initProject(); err != nil { 132 | return err 133 | } 134 | // bootstrap owner and watcher projects 135 | switch s.Options.Type { 136 | case "owner": 137 | if err := s.initOwner(); err != nil { 138 | return err 139 | } 140 | case "watcher": 141 | if err := s.initWatcher(); err != nil { 142 | return err 143 | } 144 | default: 145 | return errors.New("new projects must be created for either owner or watcher") 146 | } 147 | return nil 148 | } 149 | 150 | func (s *Session) initWatcher() error { 151 | if err := s.initWatcherContract(); err != nil { 152 | return err 153 | } 154 | if s.Config.Payload.ID != "" { 155 | if err := s.GetPayload(); err != nil { 156 | return err 157 | } 158 | } 159 | s.Config.Payload.Status = "active" 160 | return nil 161 | } 162 | 163 | func (s *Session) initWatcherContract() error { 164 | s.Config.Contract.Status = "initialized" 165 | id, err := sanitizeContractId(s.Options.Contract.ID) 166 | if err != nil { 167 | return err 168 | } 169 | s.Config.Contract.ID = id 170 | if s.Config.DevMode == true { 171 | s.Config.Contract.Mode = "testnet" 172 | } else { 173 | s.Config.Contract.Mode = "mainnet" 174 | } 175 | s.setEthereumRPCPath() 176 | s.setPayloadRPCPath() 177 | endpoint, err := GetPayloadEndpoint(id) 178 | if err != nil { 179 | return err 180 | } 181 | if endpoint == "" { 182 | fmt.Println("Payload endpoint not yet registered, skipping") 183 | return nil 184 | } else { 185 | fmt.Println("adding payload endpoint to project configuration") 186 | s.Config.Payload.ID = endpoint 187 | } 188 | key, err := GetKey(s.Config.Contract.ID) 189 | if err != nil { 190 | return err 191 | } 192 | if key != "" { 193 | fmt.Println("adding decryption key to project configuration") 194 | s.Config.Payload.Secret = key 195 | fmt.Println("decrypt the payload by running: killcord decrypt") 196 | } 197 | return nil 198 | } 199 | 200 | func (s *Session) initOwner() error { 201 | // configure payload based on Provider 202 | if err := s.initPayload(); err != nil { 203 | return err 204 | } 205 | // configure payload based on Provider 206 | if err := s.initContract(); err != nil { 207 | return err 208 | } 209 | return nil 210 | } 211 | 212 | func (s *Session) initProject() error { 213 | // check that directory is empty 214 | if err := ensureEmptyDir(); err != nil { 215 | return err 216 | } 217 | if err := createDirs(); err != nil { 218 | return err 219 | } 220 | if err := validateProjectType(s.Options.Type); err != nil { 221 | return err 222 | } 223 | if err := s.setProviders(); err != nil { 224 | return err 225 | } 226 | // set project level values 227 | s.Config.Type = s.Options.Type 228 | s.Config.Version = Version 229 | s.Config.Audience = s.Options.Audience // TODO: not sure I remember what this is 230 | s.Config.DevMode = s.Options.DevMode 231 | s.Config.Created = time.Now() 232 | s.Config.Updated = time.Now() 233 | 234 | return nil 235 | } 236 | 237 | func (s *Session) setProviders() error { 238 | // attempt to set Contract Provider from Options, or set default provider 239 | if s.Options.Contract.Provider != "" { 240 | if err := validateContractProvider(s.Options.Contract.Provider); err != nil { 241 | return err 242 | } 243 | s.Config.Contract.Provider = s.Options.Contract.Provider 244 | } else { 245 | s.Config.Contract.Provider = defaultContractProvider 246 | } 247 | 248 | // attempt to set Payload Provider from Options, or set default provider 249 | if s.Options.Payload.Provider != "" { 250 | if err := validatePayloadProvider(s.Options.Payload.Provider); err != nil { 251 | return err 252 | } 253 | s.Config.Payload.Provider = s.Options.Payload.Provider 254 | } else { 255 | s.Config.Payload.Provider = defaultPayloadProvider 256 | } 257 | return nil 258 | } 259 | 260 | func sanitizeContractId(id string) (string, error) { 261 | // check and remove "0x" if hex prefix exists 262 | if id[:2] == "0x" { 263 | id = id[2:] 264 | } 265 | // check that hex encoding is valid 266 | if _, err := hex.DecodeString(id); err != nil { 267 | return id, err 268 | } 269 | return id, nil 270 | } 271 | 272 | func validateContractProvider(p string) error { 273 | switch p { 274 | case "ethereum": 275 | default: 276 | return errors.New("invalide contract provider: " + p) 277 | } 278 | return nil 279 | } 280 | 281 | func validatePayloadProvider(p string) error { 282 | switch p { 283 | case "ipfs": 284 | default: 285 | return errors.New("invalide payload provider: " + p) 286 | } 287 | return nil 288 | } 289 | 290 | func validateProjectType(t string) error { 291 | // filter ProjectType for one of proper commands 292 | switch t { 293 | case "owner": 294 | case "publisher": 295 | case "watcher": 296 | default: 297 | return errors.New("invalide project type in options") 298 | } 299 | return nil 300 | } 301 | 302 | func (s *Session) initPayload() error { 303 | switch s.Config.Payload.Provider { 304 | case "ipfs": 305 | s.Config.Payload.Status = "initialized" 306 | default: 307 | return fmt.Errorf("error: unrecognized provider: %v\n", s.Config.Payload.Provider) 308 | } 309 | return nil 310 | } 311 | 312 | func (s *Session) initContract() error { 313 | switch s.Config.Contract.Provider { 314 | case "ethereum": 315 | if s.Config.DevMode == true { 316 | s.Config.Contract.Mode = "testnet" 317 | } else { 318 | s.Config.Contract.Mode = "mainnet" 319 | } 320 | // TODO: this needs to be reimagined thorugh interfaces 321 | if err := s.ConfigEthereum(); err != nil { 322 | return err 323 | } 324 | default: 325 | return fmt.Errorf("error: unrecognized provider: %v\n", s.Config.Contract.Provider) 326 | } 327 | return nil 328 | } 329 | 330 | func ensureEmptyDir() error { 331 | var files []string 332 | allFiles, err := filepath.Glob("*") 333 | if err != nil { 334 | return err 335 | } 336 | for _, f := range allFiles { 337 | // omit dotFiles 338 | if strings.HasPrefix(f, ".") { 339 | // skip dotFiles 340 | } else { 341 | files = append(files, f) 342 | } 343 | } 344 | if len(files) > 0 { 345 | return fmt.Errorf("error: init failed. Only init an empty directory.") 346 | } 347 | return nil 348 | } 349 | 350 | func setAbsPath() { 351 | dir, err := filepath.Abs(filepath.Dir(os.Args[0])) 352 | if err != nil { 353 | fmt.Printf("error: cannot set absolute path for project: %v\n", err) 354 | os.Exit(1) 355 | } 356 | ProjectPath = dir 357 | } 358 | 359 | func generateKey() string { 360 | key := make([]byte, 32) 361 | rand.Read(key) 362 | return hex.EncodeToString(key) 363 | } 364 | 365 | func createDirs() error { 366 | dirs := []string{ 367 | "payload/source", 368 | "payload/encrypted", 369 | "payload/decrypted", 370 | } 371 | 372 | for _, dir := range dirs { 373 | // ensure path is contructed properly for either platform 374 | pathSplit := strings.Split(dir, "/") 375 | path := filepath.Join(pathSplit...) 376 | if err := os.MkdirAll(path, 0777); err != nil { 377 | return err 378 | } 379 | } 380 | return nil 381 | } 382 | -------------------------------------------------------------------------------- /project_test.go: -------------------------------------------------------------------------------- 1 | //go:generate ./scripts/contract-gen.sh 2 | 3 | package killcord 4 | 5 | import ( 6 | "reflect" 7 | "testing" 8 | ) 9 | 10 | func TestNew(t *testing.T) { 11 | s1 := New() 12 | s2 := &Session{} 13 | 14 | if reflect.TypeOf(s1) != reflect.TypeOf(s2) { 15 | t.Fail() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /publisher.go: -------------------------------------------------------------------------------- 1 | package killcord 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "log" 7 | "time" 8 | ) 9 | 10 | const ( 11 | defaultWarningThreshold = 86400 // 24 hours 12 | defaultPublishThreshold = 172800 // 48 hours 13 | defaultPublisherMaxRetries = 5 14 | ) 15 | 16 | func (s *Session) PublishKey() error { 17 | switch s.Config.Type { 18 | case "owner": 19 | if err := SetKey(s.Config.Contract.Owner, s.Config.Contract.ID, s.Config.Payload.Secret); err != nil { 20 | return err 21 | } 22 | case "publisher": 23 | if err := SetKey(s.Config.Contract.Publisher, s.Config.Contract.ID, s.Config.Payload.Secret); err != nil { 24 | return err 25 | } 26 | default: 27 | return fmt.Errorf("project type must be `owner` or `publisher`, received: %v\n", s.Config.Type) 28 | } 29 | return nil 30 | } 31 | 32 | func (s *Session) RunPublisher() error { 33 | s.configurePublisherSession() 34 | if err := s.validatePublisherSession(); err != nil { 35 | return err 36 | } 37 | id := s.Config.Contract.ID 38 | key, err := GetKey(id) 39 | if err != nil { 40 | return err 41 | } 42 | if key != "" { 43 | return errors.New("secret key already published, skipping") 44 | } 45 | checkin, err := getLastCheckinWithRetries(defaultPublisherMaxRetries, id) 46 | if err != nil { 47 | return err 48 | } 49 | fmt.Printf("Last Checkin:\t\t%s\n", checkin) 50 | if publishThresholdReached(checkin, s.Config.Publisher.PublishThreshold) { 51 | fmt.Println("publish threshold breached, publishing secret key") 52 | if err := s.PublishKey(); err != nil { 53 | return err 54 | } 55 | return nil 56 | } 57 | if warningThresholdReached(checkin, s.Config.Publisher.WarningThreshold) { 58 | // log warning, add additional features later 59 | fmt.Println("warning: checkin has broken the warning threshold") 60 | return nil 61 | } 62 | return nil 63 | } 64 | 65 | // Configure defaults and waterfall overrides from options and Environmental variables. 66 | // config -> defaults -> options -> ENV 67 | 68 | func (s *Session) configurePublisherSession() { 69 | if s.Config.Publisher.WarningThreshold == 0 { 70 | s.Config.Publisher.WarningThreshold = defaultWarningThreshold 71 | } 72 | if s.Config.Publisher.PublishThreshold == 0 { 73 | s.Config.Publisher.PublishThreshold = defaultPublishThreshold 74 | } 75 | if s.Config.Type == "" { 76 | s.Config.Type = "publisher" 77 | } 78 | // check opts and override for session if values exist 79 | if s.Options.Publisher.WarningThreshold != 0 { 80 | s.Config.Publisher.WarningThreshold = s.Options.Publisher.WarningThreshold 81 | } 82 | if s.Options.Publisher.PublishThreshold != 0 { 83 | s.Config.Publisher.PublishThreshold = s.Options.Publisher.PublishThreshold 84 | } 85 | if s.Options.Contract.ID != "" { 86 | s.Config.Contract.ID = s.Options.Contract.ID 87 | } 88 | if s.Options.Publisher.Address != "" { 89 | s.Config.Contract.Publisher.Address = s.Options.Publisher.Address 90 | } 91 | if s.Options.Publisher.Password != "" { 92 | s.Config.Contract.Publisher.Password = s.Options.Publisher.Password 93 | } 94 | if s.Options.Publisher.KeyStore != "" { 95 | s.Config.Contract.Publisher.KeyStore = s.Options.Publisher.KeyStore 96 | } 97 | if s.Options.Payload.Secret != "" { 98 | s.Config.Payload.Secret = s.Options.Payload.Secret 99 | } 100 | } 101 | 102 | func (s *Session) validatePublisherSession() error { 103 | if s.Config.Payload.Secret == "" { 104 | return errors.New("payload secret not configured, exiting") 105 | } 106 | if s.Config.Contract.ID == "" { 107 | return errors.New("contract id not configured, exiting") 108 | } 109 | if s.Config.Contract.Publisher.Address == "" { 110 | return errors.New("publisher address not configured, exiting") 111 | } 112 | if s.Config.Contract.Publisher.Password == "" { 113 | return errors.New("publisher password not configured, exiting") 114 | } 115 | 116 | if s.Config.Contract.Publisher.KeyStore == "" { 117 | return errors.New("publisher keystore not configured, exiting") 118 | } 119 | 120 | if s.Config.Publisher.WarningThreshold == 0 { 121 | return errors.New("warning threshold not configured, exiting") 122 | } 123 | 124 | if s.Config.Publisher.PublishThreshold == 0 { 125 | return errors.New("publish threshold not configured, exiting") 126 | } 127 | return nil 128 | } 129 | 130 | func warningThresholdReached(checkin time.Time, warningThreshold int64) bool { 131 | threshold := time.Now().Unix() - warningThreshold 132 | fmt.Printf("Warning Threshold:\t%s\n", time.Unix(threshold, 0)) 133 | if checkin.Unix() <= threshold { 134 | return true 135 | } 136 | return false 137 | } 138 | 139 | func publishThresholdReached(checkin time.Time, publishThreshold int64) bool { 140 | threshold := time.Now().Unix() - publishThreshold 141 | fmt.Printf("Publish Threshold:\t%s\n", time.Unix(threshold, 0)) 142 | if checkin.Unix() <= threshold { 143 | return true 144 | } 145 | return false 146 | } 147 | 148 | func getLastCheckinWithRetries(maxRetries int, id string) (time.Time, error) { 149 | for retry := 1; retry <= maxRetries; retry++ { 150 | checkin, err := GetLastCheckIn(id) 151 | if err != nil { 152 | fmt.Println("checkin failed, retrying: ", err) 153 | time.Sleep(1 * time.Second) 154 | continue 155 | } 156 | return checkin, nil 157 | } 158 | return time.Time{}, fmt.Errorf("checkin max retry of %v reached, skipping\n", maxRetries) 159 | } 160 | 161 | func (s *Session) PublisherLambdaHandler() { 162 | if err := s.RunPublisher(); err != nil { 163 | log.Println(err) 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /publisher_test.go: -------------------------------------------------------------------------------- 1 | package killcord 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | func TestPublishKey(t *testing.T) { 9 | session := New() 10 | session.Config.Type = "bogus" 11 | if err := session.PublishKey(); err != nil { 12 | if err.Error() != "project type must be `owner` or `publisher`, received: bogus\n" { 13 | t.Fail() 14 | } 15 | } 16 | } 17 | 18 | func TestPublishThresholdReached(t *testing.T) { 19 | testTable := []struct { 20 | checkin time.Time 21 | threshold int64 22 | expected bool 23 | }{ 24 | {time.Now(), defaultPublishThreshold, false}, 25 | {time.Now().AddDate(0, 0, -1), defaultPublishThreshold, false}, 26 | {time.Now().AddDate(0, 0, -4), defaultPublishThreshold, true}, 27 | } 28 | 29 | for _, test := range testTable { 30 | if r := publishThresholdReached(test.checkin, test.threshold); r != test.expected { 31 | t.Errorf("checkin: %v threshold: %v was %v, expected %v", test.checkin, test.threshold, r, test.expected) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /scripts/build-release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # the idea hear is to generate prebuilt binaries of kilcord to work on 4 | # the killcord website. This will expand over time (I see rasberry pi 5 | # in the near future) 6 | # 7 | # the format for adding this to 8 | # killcord.io/killcord/0.0.1-alpha/killcord_0.0.1-alpha_macos_64bit.zip 9 | 10 | # exit on error 11 | set -e 12 | 13 | # setup boiler plate 14 | PROJECT="killcord" 15 | BUCKET="s3://killcord.io" 16 | CODE_PLATFORM="null" 17 | CODE_ARCH="null" 18 | 19 | # get platform name 20 | case "$(uname -s)" in 21 | Linux*) 22 | CODE_PLATFORM="linux" 23 | ;; 24 | Darwin*) 25 | CODE_PLATFORM="macos" 26 | ;; 27 | *) 28 | echo "unsupported OS, exiting" 29 | exit 1 30 | esac 31 | 32 | case "$(uname -m)" in 33 | x86_64) CODE_ARCH="amd64" ;; 34 | x86) CODE_ARCH="386" ;; 35 | i686) CODE_ARCH="386" ;; 36 | i386) CODE_ARCH="386" ;; 37 | aarch64) CODE_ARCH="arm64" ;; 38 | armv5*) CODE_ARCH="arm5" ;; 39 | armv6*) CODE_ARCH="arm6" ;; 40 | armv7*) CODE_ARCH="arm7" ;; 41 | *) echo "unsupported architecture for this tool, exiting" && exit 1 42 | esac 43 | 44 | # go to the cmd directory 45 | cd $PROJECT 46 | 47 | # build it 48 | echo "building killcord for $CODE_PLATFORM $CODE_ARCH" 49 | go build 50 | 51 | # grab the version 52 | PROJECT_VERSION="$(./killcord version)" 53 | 54 | # name it 55 | ZIP_NAME=$PROJECT\_$PROJECT_VERSION\_$CODE_PLATFORM\_$CODE_ARCH.zip 56 | 57 | # zip it 58 | zip $ZIP_NAME $PROJECT 59 | 60 | # upload it 61 | aws s3 cp $ZIP_NAME $BUCKET/$PROJECT/$PROJECT_VERSION/$ZIP_NAME --acl public-read 62 | 63 | # clean it 64 | rm $PROJECT $ZIP_NAME 65 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | PROJ=killcord 5 | 6 | ## used to build the cli tool from source while killcord 7 | ## was in private development 8 | 9 | cd $PROJ 10 | go build 11 | mv $PROJ $HOME/bin/$PROJ -------------------------------------------------------------------------------- /scripts/contract-gen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | CONTRACT_PATH='./contract' 5 | 6 | ## Generate abi and bin files from contract (force overwrite) 7 | solc --overwrite --abi --bin $CONTRACT_PATH/killcord.sol -o $CONTRACT_PATH 8 | 9 | ## generate contract library in go for use with killcord contract 10 | abigen \ 11 | --abi $CONTRACT_PATH/killcord.abi \ 12 | --pkg contract \ 13 | --type KillCord \ 14 | --out $CONTRACT_PATH/killcord.go \ 15 | --bin $CONTRACT_PATH/killcord.bin -------------------------------------------------------------------------------- /status.go: -------------------------------------------------------------------------------- 1 | //go:generate ./scripts/contract-gen.sh 2 | //go:generate ./scripts/build.sh 3 | 4 | package killcord 5 | 6 | import ( 7 | "fmt" 8 | ) 9 | 10 | func (s *Session) GetStatus() error { 11 | if err := s.getProjectStatus(); err != nil { 12 | return err 13 | } 14 | if err := s.getContractStatus(); err != nil { 15 | return err 16 | } 17 | if err := s.getPayloadStatus(); err != nil { 18 | return err 19 | } 20 | if err := s.getPublisherStatus(); err != nil { 21 | return err 22 | } 23 | return nil 24 | } 25 | 26 | func (s *Session) getProjectStatus() error { 27 | fmt.Println("") 28 | fmt.Printf("Project Status:\t\t\t%v\n", s.Config.Status) 29 | fmt.Println("--------------") 30 | return nil 31 | } 32 | 33 | func (s *Session) getContractStatus() error { 34 | fmt.Println("") 35 | fmt.Printf("Contract Status:\t\t%v\n", s.Config.Contract.Status) 36 | fmt.Println("---------------") 37 | var registeredOwnerAddress, registeredPublisherAddress string 38 | if s.Config.Contract.ID != "" { 39 | fmt.Printf("\tContract ID:\t\t0x%v\n", s.Config.Contract.ID) 40 | 41 | // get last checkin 42 | checkin, err := GetLastCheckIn(s.Config.Contract.ID) 43 | if err != nil { 44 | return err 45 | } 46 | fmt.Printf("\tLast Checkin:\t\t%v\n", checkin) 47 | 48 | // get endpoint info 49 | endpoint, err := GetPayloadEndpoint(s.Config.Contract.ID) 50 | if err != nil { 51 | return err 52 | } 53 | if endpoint == "" { 54 | endpoint = "not configured" 55 | } 56 | fmt.Printf("\tRegistered Endpoint:\t%v\n", endpoint) 57 | 58 | // get Key info 59 | key, err := GetKey(s.Config.Contract.ID) 60 | if err != nil { 61 | return err 62 | } 63 | // if key is written to the contract and it does not 64 | // exist in the config, write it to the config 65 | if key != "" && s.Config.Payload.Secret == "" { 66 | s.Config.Payload.Secret = key 67 | fmt.Println("payload secret discovered, writing to config") 68 | fmt.Println("to decrypt the payload run: killcord decrypt") 69 | } 70 | if key == "" { 71 | key = "not published" 72 | } 73 | fmt.Printf("\tDecryption Key:\t\t%v\n", key) 74 | 75 | registeredOwnerAddress, err = GetOwner(s.Config.Contract.ID) 76 | if err != nil { 77 | return err 78 | } 79 | registeredPublisherAddress, err = GetPublisher(s.Config.Contract.ID) 80 | if err != nil { 81 | return err 82 | } 83 | } 84 | 85 | if s.Config.Contract.Owner.Address != "" { 86 | OwnBal := getBalance(s.Config.Contract.Owner.Address) 87 | fmt.Printf("\tOwner Balance:\t\t%v\n", OwnBal) 88 | } 89 | if s.Config.Contract.Owner.Address != "" { 90 | fmt.Printf("\tOwner (local):\t\t%v\n", "0x"+s.Config.Contract.Owner.Address) 91 | } 92 | if registeredOwnerAddress != "" { 93 | fmt.Printf("\tOwner (contract):\t%v\n", registeredOwnerAddress) 94 | } 95 | if s.Config.Contract.Publisher.Address != "" { 96 | pubBal := getBalance(s.Config.Contract.Publisher.Address) 97 | fmt.Printf("\tPublisher Balance:\t%v\n", pubBal) 98 | } 99 | if s.Config.Contract.Publisher.Address != "" { 100 | fmt.Printf("\tPublisher (local):\t%v\n", "0x"+s.Config.Contract.Publisher.Address) 101 | } 102 | if registeredPublisherAddress != "" { 103 | fmt.Printf("\tPublisher (contract):\t%v\n", registeredPublisherAddress) 104 | } 105 | return nil 106 | } 107 | 108 | func (s *Session) getPayloadStatus() error { 109 | fmt.Println("") 110 | fmt.Printf("Payload Status:\t\t\t%v\n", s.Config.Payload.Status) 111 | fmt.Println("--------------") 112 | return nil 113 | } 114 | 115 | func (s *Session) getPublisherStatus() error { 116 | fmt.Println("") 117 | fmt.Printf("Publisher Status:\t\t%v\n", s.Config.Publisher.Status) 118 | fmt.Println("----------------") 119 | return nil 120 | } 121 | -------------------------------------------------------------------------------- /status_test.go: -------------------------------------------------------------------------------- 1 | package killcord 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // need to write real tests for this... 8 | 9 | func TestGetStatus(t *testing.T) { 10 | session := New() 11 | err := session.GetStatus() 12 | if err != nil { 13 | t.Fail() 14 | } 15 | } 16 | 17 | func TestGetProjectStatus(t *testing.T) { 18 | session := New() 19 | err := session.getProjectStatus() 20 | if err != nil { 21 | t.Fail() 22 | } 23 | } 24 | 25 | func TestGetContractStatus(t *testing.T) { 26 | session := New() 27 | err := session.getContractStatus() 28 | if err != nil { 29 | t.Fail() 30 | } 31 | 32 | } 33 | 34 | func TestGetPublisherStatus(t *testing.T) { 35 | session := New() 36 | err := session.getPublisherStatus() 37 | if err != nil { 38 | t.Fail() 39 | } 40 | } 41 | 42 | func TestGetPayloadStatus(t *testing.T) { 43 | session := New() 44 | err := session.getPayloadStatus() 45 | if err != nil { 46 | t.Fail() 47 | } 48 | } 49 | --------------------------------------------------------------------------------