Initial Commit: a dirty mess, just the way I like it

master
Hugo Thunnissen 2 years ago
commit 14b55747e5

@ -0,0 +1,145 @@
package main
import (
"errors"
"io"
"time"
ipfsapi "github.com/ipfs/go-ipfs-api"
"golang.org/x/net/context"
)
type File struct {
Name string `json:"name"`
AbsolutePath string `json:"absolute_path"`
Contents io.Reader `json:"-"`
}
type Filestore interface {
Get(name string) (*File, error)
Set(file *File) error
Delete(file *File) error
Exists(name string) (bool, error)
}
func NewIPFSFilestore(ipfs *ipfsapi.Shell, rootDir string) (*IPFSFilestore, error) {
store := &IPFSFilestore{
ipfs: ipfs,
rootDir: rootDir,
}
exists, err := store.Exists("")
if err != nil {
return nil, err
}
if !exists {
err := ipfs.FilesMkdir(newContext(), rootDir)
if err != nil {
return nil, err
}
}
return store, nil
}
type IPFSFilestore struct {
ipfs *ipfsapi.Shell
rootDir string
}
var ErrFileNotFound = errors.New("File not found")
type ErrFailedFileExistsCheck struct {
parent error
}
func (e *ErrFailedFileExistsCheck) Unwrap() error {
return e.parent
}
func (e *ErrFailedFileExistsCheck) Error() string {
msg := "Failed to determine whether file exists"
if e.parent != nil {
msg += ": " + e.parent.Error()
}
return msg
}
func newContext() context.Context {
ctx, _ := context.WithTimeout(context.Background(), 10*time.Minute)
return ctx
}
func (s *IPFSFilestore) Exists(name string) (bool, error) {
ctx := newContext()
_, err := s.ipfs.FilesStat(ctx, s.rootDir+"/"+name)
if err != nil {
if err.Error() == "files/stat: file does not exist" {
return false, nil
}
return false, &ErrFailedFileExistsCheck{parent: err}
}
return true, nil
}
type FileReader struct {
ipfs *ipfsapi.Shell
file *File
reader io.ReadCloser
}
func (r *FileReader) Read(p []byte) (int, error) {
if r.reader == nil {
var err error
r.reader, err = r.ipfs.FilesRead(newContext(), r.file.AbsolutePath)
if err != nil {
return 0, err
}
}
return r.reader.Read(p)
}
func (r *FileReader) Close() error {
if r.reader == nil {
return nil
}
return r.reader.Close()
}
func (s *IPFSFilestore) Get(name string) (*File, error) {
exists, err := s.Exists(name)
if err != nil {
return nil, err
}
if !exists {
return nil, ErrFileNotFound
}
file := &File{
Name: name,
AbsolutePath: s.rootDir + "/" + name,
}
file.Contents = &FileReader{
ipfs: s.ipfs,
file: file,
}
return file, nil
}
func (s *IPFSFilestore) Set(file *File) error {
return s.ipfs.FilesWrite(newContext(), s.rootDir+"/"+file.Name, file.Contents)
}
func (s *IPFSFilestore) Delete(file *File) error {
return s.ipfs.FilesRm(newContext(), file.AbsolutePath, true)
}

@ -0,0 +1,42 @@
module git.snorba.art/hugo/nssh
go 1.18
require (
github.com/SkynetLabs/go-skynet/v2 v2.1.0 // indirect
github.com/btcsuite/btcd v0.22.1 // indirect
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect
github.com/creack/pty v1.1.18 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/ipfs/go-cid v0.2.0 // indirect
github.com/ipfs/go-ipfs-api v0.3.0 // indirect
github.com/ipfs/go-ipfs-files v0.1.1 // indirect
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
github.com/libp2p/go-flow-metrics v0.0.3 // indirect
github.com/libp2p/go-libp2p-core v0.15.1 // indirect
github.com/libp2p/go-openssl v0.0.7 // indirect
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.0.4 // indirect
github.com/multiformats/go-base36 v0.1.0 // indirect
github.com/multiformats/go-multiaddr v0.5.0 // indirect
github.com/multiformats/go-multibase v0.0.3 // indirect
github.com/multiformats/go-multicodec v0.4.1 // indirect
github.com/multiformats/go-multihash v0.1.0 // indirect
github.com/multiformats/go-varint v0.0.6 // indirect
github.com/pkg/term v1.1.0 // indirect
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/whyrusleeping/tar-utils v0.0.0-20201201191210-20a61371de5b // indirect
gitlab.com/NebulousLabs/errors v0.0.0-20200929122200-06c536cf6975 // indirect
go.opencensus.io v0.23.0 // indirect
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
lukechampine.com/blake3 v1.1.7 // indirect
)

252
go.sum

@ -0,0 +1,252 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/SkynetLabs/go-skynet/v2 v2.1.0 h1:fYUoe2Lu8epLBkd+B2jaKbS82KQ2Vv+eqLG0R8zMwZM=
github.com/SkynetLabs/go-skynet/v2 v2.1.0/go.mod h1:XOk0zwGlXeGjHQgmhXTEk7qTD6FVv3dXPW38Wh3XsIc=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c=
github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg=
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
github.com/ipfs/go-cid v0.2.0 h1:01JTiihFq9en9Vz0lc0VDWvZe/uBonGpzo4THP0vcQ0=
github.com/ipfs/go-cid v0.2.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro=
github.com/ipfs/go-ipfs-api v0.3.0 h1:ZzVrsTV31Z53ZlUare6a5UJ46lC7lW93q/s1/fXyATk=
github.com/ipfs/go-ipfs-api v0.3.0/go.mod h1:A1naQGm0Jg01GxDq7oDyVSZxt20SuRTNIBFNZJgPDmg=
github.com/ipfs/go-ipfs-files v0.0.9/go.mod h1:aFv2uQ/qxWpL/6lidWvnSQmaVqCrf0TBGoUr+C1Fo84=
github.com/ipfs/go-ipfs-files v0.1.1 h1:/MbEowmpLo9PJTEQk16m9rKzUHjeP4KRU9nWJyJO324=
github.com/ipfs/go-ipfs-files v0.1.1/go.mod h1:8xkIrMWH+Y5P7HvJ4Yc5XWwIW2e52dyXUiC0tZyjDbM=
github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ=
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs=
github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=
github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM=
github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
github.com/libp2p/go-libp2p-core v0.15.1 h1:0RY+Mi/ARK9DgG1g9xVQLb8dDaaU8tCePMtGALEfBnM=
github.com/libp2p/go-libp2p-core v0.15.1/go.mod h1:agSaboYM4hzB1cWekgVReqV5M4g5M+2eNNejV+1EEhs=
github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA=
github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw=
github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE=
github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM=
github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4=
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y=
github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI=
github.com/multiformats/go-multiaddr v0.5.0 h1:i/JuOoVg4szYQ4YEzDGtb2h0o8M7CG/Yq6cGlcjWZpM=
github.com/multiformats/go-multiaddr v0.5.0/go.mod h1:3KAxNkUqLTJ20AAwN4XVX4kZar+bR+gh4zgbfr3SNug=
github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk=
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
github.com/multiformats/go-multicodec v0.4.1 h1:BSJbf+zpghcZMZrwTYBGwy0CPcVZGWiC72Cp8bBd4R4=
github.com/multiformats/go-multicodec v0.4.1/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ=
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
github.com/multiformats/go-multihash v0.1.0 h1:CgAgwqk3//SVEw3T+6DqI4mWMyRuDwZtOWcJT0q9+EA=
github.com/multiformats/go-multihash v0.1.0/go.mod h1:RJlXsxt6vHGaia+S8We0ErjhojtKzPP2AH4+kYM7k84=
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pkg/term v1.1.0 h1:xIAAdCMh3QIAy+5FrE8Ad8XoDhEU4ufwbaSozViP9kk=
github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/whyrusleeping/tar-utils v0.0.0-20180509141711-8c6c8ba81d5c/go.mod h1:xxcJeBb7SIUl/Wzkz1eVKJE/CB34YNrqX2TQI6jY9zs=
github.com/whyrusleeping/tar-utils v0.0.0-20201201191210-20a61371de5b h1:wA3QeTsaAXybLL2kb2cKhCAQTHgYTMwuI8lBlJSv5V8=
github.com/whyrusleeping/tar-utils v0.0.0-20201201191210-20a61371de5b/go.mod h1:xT1Y5p2JR2PfSZihE0s4mjdJaRGp1waCTf5JzhQLBck=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
gitlab.com/NebulousLabs/errors v0.0.0-20171229012116-7ead97ef90b8/go.mod h1:ZkMZ0dpQyWwlENaeZVBiQRjhMEZvk6VTXquzl3FOFP8=
gitlab.com/NebulousLabs/errors v0.0.0-20200929122200-06c536cf6975 h1:L/ENs/Ar1bFzUeKx6m3XjlmBgIUlykX9dzvp5k9NGxc=
gitlab.com/NebulousLabs/errors v0.0.0-20200929122200-06c536cf6975/go.mod h1:ZkMZ0dpQyWwlENaeZVBiQRjhMEZvk6VTXquzl3FOFP8=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=

@ -0,0 +1,324 @@
package main
import (
"errors"
"fmt"
"log"
"strconv"
"strings"
"golang.org/x/sys/unix"
)
type CommandHandler struct {
shell *Shell
filestore Filestore
}
func NewCommandHandler(shell *Shell, filestore Filestore) *CommandHandler {
return &CommandHandler{
shell: shell,
filestore: filestore,
}
}
func Control(c rune) rune {
return c & 0x1f
}
func sttyCharFromDesc(c string) (rune, error) {
if len(c) > 2 || len(c) < 1 {
return 'i', errors.New(
"stty char description has unsupported length: " +
strconv.Itoa(len(c)),
)
}
if rune(c[0]) == '^' {
return Control(rune(c[1])), nil
}
return rune(c[0]), nil
}
const fakeUname = "Linux 5.16.19-76051619-generic"
type CommandExecutor interface {
Execute(shell *Shell, args []string) error
}
type SttyCommand struct{}
func (c *SttyCommand) Execute(shell *Shell, args []string) error {
// Tramp uses:
// -inlcr: don't translate newline to carriage return
// -onlcr: don't translate newline to carriage return-newline
// -echo: echo input characters
// kill CHAR: CHAR will erase the current line
// erase CHAR: CHAR will erase the last character typed
// icanon: enable special charactersq
fd := int(shell.GetPty().Fd())
const ioctlReadTermios = unix.TCGETS // Linux
const ioctlWriteTermios = unix.TCSETS // Linux
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
if err != nil {
panic(err)
}
newState := *termios
var skipNext bool
for i, arg := range args {
if skipNext {
skipNext = false
continue
}
var disable bool
if arg[0] == '-' {
disable = true
arg = arg[1:]
}
switch arg {
case "onlcr":
if disable {
newState.Iflag &^= unix.ONLCR
continue
}
newState.Iflag |= unix.ONLCR
case "inlcr":
if disable {
newState.Iflag &^= unix.INLCR
continue
}
newState.Iflag |= unix.INLCR
case "echo":
if disable {
newState.Lflag &^= unix.ECHO
continue
}
newState.Lflag |= unix.ECHO
case "kill":
skipNext = true
char, err := sttyCharFromDesc(args[i+1])
if err != nil {
log.Printf(
"Warning: Not applying unsupported character description for stty kill: %s",
args[i+1],
)
continue
}
newState.Cc[unix.VKILL] = uint8(char)
case "erase":
skipNext = true
char, err := sttyCharFromDesc(args[i+1])
if err != nil {
log.Printf(
"Warning: Not applying unsupported character description for stty erase: %s",
args[i+1],
)
continue
}
newState.Cc[unix.VERASE] = uint8(char)
case "icanon":
if disable {
newState.Lflag &^= unix.ICANON
continue
}
newState.Lflag |= unix.ICANON
case "tab0":
newState.Oflag = (newState.Oflag & ^uint32(unix.TABDLY)) | unix.TAB0
case "iutf8":
if disable {
newState.Iflag &^= unix.IUTF8
continue
}
newState.Iflag |= unix.IUTF8
default:
log.Printf(
"Warning, tramp requested unexpected stty option %s",
arg,
)
}
}
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, &newState); err != nil {
return err
}
return nil
}
type EchoCommand struct{}
func (c *EchoCommand) Execute(shell *Shell, args []string) error {
if len(args) > 1 {
if "\"`uname -sr`\"" == args[0]+" "+args[1] {
log.Println("Tramp requested uname, returning a fake one: " + fakeUname)
_, err := shell.WriteOutput(
[]byte(
fmt.Sprintf(
"\"%s\"\n%s\n",
fakeUname,
"tramp_exit_status 0",
),
),
)
return err
}
if "\"`tty`\"" == args[0] {
log.Println("Telling tramp that it's dealing with a tty")
_, err := shell.WriteOutputString("\"/dev/pts/0\"\n" + trampSuccess)
return err
}
}
if len(args) > 0 {
if args[0] == "~root" {
log.Println("Telling tramp root's home directory")
_, err := shell.WriteOutputString("/root")
return err
}
}
_, err := shell.WriteOutput([]byte(strings.Join(args, " ") + "\n"))
return err
}
func AssignmentsToMap(args []string) map[string]string {
var assignments = make(map[string]string)
for _, arg := range args {
split := strings.Split(arg, "=")
if len(split) > 1 {
assignments[split[0]] = split[1]
}
}
return assignments
}
func ApplyEnvIfPresent(shell *Shell, comm *Command) {
var args []string
args = append(args, comm.Name)
args = append(args, comm.Arguments...)
assignments := AssignmentsToMap(args)
if ps1, ok := assignments["PS1"]; ok {
shell.SetPrompt(ps1)
}
}
type TestCommand struct {
filestore Filestore
}
func (c *TestCommand) Execute(shell *Shell, args []string) error {
if len(args) > 0 && args[0] == "0" {
_, err := shell.WriteOutputString(trampSuccess)
return err
}
if len(args) > 1 && args[0] == "-d" {
log.Printf("Checking for existance of directory %s", args[1])
exists, err := c.filestore.Exists(args[1])
if err != nil {
return err
}
if exists {
_, err := shell.WriteOutputString(trampSuccess)
return err
}
_, err = shell.WriteOutputString(trampFailure)
return err
}
if len(args) > 1 && args[0] == "-r" {
_, err := shell.WriteOutputString(trampSuccess)
return err
}
return nil
}
const fakePath = "/bin:/usr/bin"
const fakePipeBuf = "4096"
const trampSuccess = "tramp_exit_status 0\n"
const trampFailure = "tramp_exit_status 1\n"
type GetConfCommand struct{}
func (c *GetConfCommand) Execute(shell *Shell, args []string) error {
if len(args) > 0 {
switch args[0] {
case "PATH":
shell.WriteOutputString(fakePath + "\n" + trampSuccess)
case "PIPE_BUF":
shell.WriteOutputString(fakePipeBuf + "\n" + trampSuccess)
}
}
return nil
}
func (h *CommandHandler) Handle(comm *Command) error {
if strings.Contains(comm.Name, "=") {
ApplyEnvIfPresent(h.shell, comm)
return nil
}
switch comm.Name {
case "exec":
ApplyEnvIfPresent(h.shell, comm)
case "(cd":
h.shell.WriteOutput([]byte("tramp_exit_status 0\n"))
case "echo":
(&EchoCommand{}).Execute(h.shell, comm.Arguments)
case "(echo":
if strings.Join(comm.Arguments, " ") == "foo ; echo bar)" {
log.Println("Handling tramp's foobar test")
h.shell.WriteOutputString("foo\nbar\n")
}
case "stty":
return (&SttyCommand{}).Execute(h.shell, comm.Arguments)
case "set":
log.Println("Ignoring \"set\" command")
case "locale":
if len(comm.Arguments) > 0 {
if comm.Arguments[0] == "-a" {
locales := []string{"C", "C.UTF-8", "POSIX", "en_US.utf8"}
log.Println("Tramp requested locale, returning fake values: ", locales)
h.shell.WriteOutputString(
strings.Join(locales, "\n") + "\n",
)
return nil
}
}
log.Println("Ignoring \"locale\" command with unsupported parameters: ", comm.Arguments)
case "getconf":
return (&GetConfCommand{}).Execute(h.shell, comm.Arguments)
case "test":
return (&TestCommand{filestore: h.filestore}).Execute(h.shell, comm.Arguments)
default:
log.Printf("Error: Received unexpected command %s", comm.Name)
}
return nil
}

@ -0,0 +1,289 @@
2022/05/05 11:04:59 Private Key generated
2022/05/05 11:05:06 logged in with key SHA256:e+GGc8xMdIe6nXdohM3LR8s2H4moA8zffv8CP5WjB8M
2022/05/05 11:05:06 received request of type "pty-req"
2022/05/05 11:05:06 window resize 106x42
2022/05/05 11:05:06 pty-req 'xterm-256color'
2022/05/05 11:05:06 received request of type "env"
2022/05/05 11:05:06 received request of type "env"
2022/05/05 11:05:06 received request of type "env"
2022/05/05 11:05:06 received request of type "env"
2022/05/05 11:05:06 received request of type "env"
2022/05/05 11:05:06 received request of type "env"
2022/05/05 11:05:06 received request of type "env"
2022/05/05 11:05:06 received request of type "env"
2022/05/05 11:05:06 received request of type "env"
2022/05/05 11:05:06 received request of type "env"
2022/05/05 11:05:06 received request of type "env"
2022/05/05 11:05:06 received request of type "env"
2022/05/05 11:05:06 received request of type "env"
2022/05/05 11:05:06 received request of type "shell"
2022/05/05 11:05:09 command: "ls" []
2022/05/05 11:05:09 Error: Received unexpected command ls
2022/05/05 11:05:26 command: "test" [-d /var/www]
2022/05/05 11:05:26 Checking for existance of directory /var/www
2022/05/05 11:06:36 command: "locale" []
2022/05/05 11:06:36 Ignoring "locale" command with unsupported parameters: []
2022/05/05 11:06:39 command: "locale" [-a]
2022/05/05 11:06:39 Tramp requested locale, returning fake values: [C C.UTF-8 POSIX en_US.utf8]
2022/05/05 11:07:01 command: "exec" []
2022/05/05 11:07:08 command: "PS1=hallo" []
2022/05/05 11:07:08 Changing prompt to "hallo"
2022/05/05 11:07:21 command: "exec" [PS1=heey]
2022/05/05 11:07:21 Changing prompt to "heey"
2022/05/05 11:07:35 command: "exec" [HAAi=DOEI PS1=heeaaaa]
2022/05/05 11:07:35 Changing prompt to "heeaaaa"
2022/05/05 11:08:57 command: "echo" [heeeeey]
2022/05/05 11:09:06 Received EOF, closing TTY
2022/05/05 11:09:06 logged in with key SHA256:e+GGc8xMdIe6nXdohM3LR8s2H4moA8zffv8CP5WjB8M
2022/05/05 11:09:06 received request of type "pty-req"
2022/05/05 11:09:06 window resize 106x42
2022/05/05 11:09:06 pty-req 'xterm-256color'
2022/05/05 11:09:06 received request of type "env"
2022/05/05 11:09:06 received request of type "env"
2022/05/05 11:09:06 received request of type "env"
2022/05/05 11:09:06 received request of type "env"
2022/05/05 11:09:06 received request of type "env"
2022/05/05 11:09:06 received request of type "env"
2022/05/05 11:09:06 received request of type "env"
2022/05/05 11:09:06 received request of type "env"
2022/05/05 11:09:06 received request of type "env"
2022/05/05 11:09:06 received request of type "env"
2022/05/05 11:09:06 received request of type "env"
2022/05/05 11:09:06 received request of type "env"
2022/05/05 11:09:06 received request of type "env"
2022/05/05 11:09:06 received request of type "shell"
2022/05/05 11:09:11 command: "echo" [heey]
2022/05/05 11:09:16 command: "echo" [
faiwiefjawiejfwae
ajeifwajef
]
2022/05/05 11:09:38 Heredoc current word: "HAAAAAA"
2022/05/05 11:09:38 Encountered heredoc marker: HAAAAAA
2022/05/05 11:09:40 Heredoc current word: "fijwoiajfawoie"
2022/05/05 11:09:40 Heredoc current word: "afjwaoeifj"
2022/05/05 11:09:41 Heredoc current word: "awfjoiwjfe"
2022/05/05 11:09:41 Heredoc current word: ""
2022/05/05 11:09:42 Heredoc current word: "jawif;eijaw"
2022/05/05 11:09:42 Heredoc current word: ""
2022/05/05 11:09:49 Heredoc current word: "HAAAAAAA"
2022/05/05 11:09:59 Heredoc current word: "HAAAAAA"
2022/05/05 11:09:59 exiting heredoc
2022/05/05 11:09:59 command: "while" [read -r heey; do hahahaha; done <<HAAAAAA fijwoiajfawoie afjwaoeifj awfjoiwjfe jawif;eijaw HAAAAAAA HAAAAAA]
2022/05/05 11:09:59 Error: Received unexpected command while
2022/05/05 11:10:24 Received EOF, closing TTY
2022/05/05 11:11:22 logged in with key SHA256:e+GGc8xMdIe6nXdohM3LR8s2H4moA8zffv8CP5WjB8M
2022/05/05 11:11:22 received request of type "pty-req"
2022/05/05 11:11:22 window resize 106x42
2022/05/05 11:11:22 pty-req 'xterm-256color'
2022/05/05 11:11:22 received request of type "env"
2022/05/05 11:11:22 received request of type "env"
2022/05/05 11:11:22 received request of type "env"
2022/05/05 11:11:22 received request of type "env"
2022/05/05 11:11:22 received request of type "env"
2022/05/05 11:11:22 received request of type "env"
2022/05/05 11:11:22 received request of type "env"
2022/05/05 11:11:22 received request of type "env"
2022/05/05 11:11:22 received request of type "env"
2022/05/05 11:11:22 received request of type "env"
2022/05/05 11:11:22 received request of type "env"
2022/05/05 11:11:22 received request of type "env"
2022/05/05 11:11:22 received request of type "env"
2022/05/05 11:11:22 received request of type "shell"
2022/05/05 11:11:25 command: "stty" [-echo]
2022/05/05 11:11:29 command: "fjieawif;waiejf;iajwf;awijef;aiwjf;awijef;oaiwejf;awiej;ijw" []
2022/05/05 11:11:29 Error: Received unexpected command fjieawif;waiejf;iajwf;awijef;aiwjf;awijef;oaiwejf;awiej;ijw
2022/05/05 11:11:34 Received EOF, closing TTY
2022/05/05 12:18:04 logged in with key SHA256:e+GGc8xMdIe6nXdohM3LR8s2H4moA8zffv8CP5WjB8M
2022/05/05 12:18:04 received request of type "pty-req"
2022/05/05 12:18:04 window resize 0x0
2022/05/05 12:18:04 pty-req 'dumb'
2022/05/05 12:18:04 received request of type "env"
2022/05/05 12:18:04 received request of type "env"
2022/05/05 12:18:04 received request of type "env"
2022/05/05 12:18:04 received request of type "env"
2022/05/05 12:18:04 received request of type "env"
2022/05/05 12:18:04 received request of type "env"
2022/05/05 12:18:04 received request of type "env"
2022/05/05 12:18:04 received request of type "env"
2022/05/05 12:18:04 received request of type "env"
2022/05/05 12:18:04 received request of type "env"
2022/05/05 12:18:04 received request of type "env"
2022/05/05 12:18:04 received request of type "env"
2022/05/05 12:18:04 received request of type "env"
2022/05/05 12:18:04 received request of type "env"
2022/05/05 12:18:04 received request of type "shell"
2022/05/05 12:18:04 command: "exec" [env TERM=dumb INSIDE_EMACS=27.2,tramp:2.4.5.27.2 ENV= HISTFILE=~/.tramp_history PROMPT_COMMAND= PS1=#$ PS2= PS3= /bin/sh]
2022/05/05 12:18:04 Changing prompt to "#$ "
2022/05/05 12:18:04 command: "(cd" [~/) 2>/dev/null; echo tramp_exit_status $?]
2022/05/05 12:18:04 command: "set" [+o vi +o emacs]
2022/05/05 12:18:04 Ignoring "set" command
2022/05/05 12:18:04 command: "stty" [-inlcr -onlcr -echo kill ^U erase ^H]
2022/05/05 12:18:04 command: "echo" [foo]
2022/05/05 12:18:04 command: "PS1=///eac57010bddba5dae79f08f3cd43067c#$" [PS2= PS3= PROMPT_COMMAND=]
2022/05/05 12:18:04 Changing prompt to "///eac57010bddba5dae79f08f3cd43067c#$"
2022/05/05 12:18:04 command: "echo" ["`uname -sr`" 2>/dev/null; echo tramp_exit_status $?]
2022/05/05 12:18:04 Tramp requested uname, returning a fake one: Linux 5.16.19-76051619-generic
2022/05/05 12:18:04 command: "(echo" [foo ; echo bar)]
2022/05/05 12:18:04 Handling tramp's foobar test
2022/05/05 12:18:04 command: "PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/local/bin:/local/freeware/bin:/local/gnu/bin:/usr/freeware/bin:/usr/pkg/bin:/usr/contrib/bin:/opt/bin:/opt/sbin:/opt/local/bin" [&& export PATH]
2022/05/05 12:18:04 command: "mesg" [n 2>/dev/null; biff n 2>/dev/null]
2022/05/05 12:18:04 Error: Received unexpected command mesg
2022/05/05 12:18:04 command: "stty" [tab0]
2022/05/05 12:18:04 command: "stty" [iutf8 2>/dev/null]
2022/05/05 12:18:04 Warning, tramp requested unexpected stty option 2>/dev/null
2022/05/05 12:18:04 command: "echo" ["`tty`" 2>/dev/null; echo tramp_exit_status $?]
2022/05/05 12:18:04 Telling tramp that it's dealing with a tty
2022/05/05 12:18:04 Heredoc current word: "'cf8110e8e028188d140944ad469ceb8f'"
2022/05/05 12:18:04 Encountered heredoc marker: 'cf8110e8e028188d140944ad469ceb8f'
2022/05/05 12:18:04 Heredoc current word: "LC_ALL en_US.utf8"
2022/05/05 12:18:04 Heredoc current word: "ENV ''"
2022/05/05 12:18:04 Heredoc current word: "TMOUT 0"
2022/05/05 12:18:04 Heredoc current word: "LC_CTYPE ''"
2022/05/05 12:18:04 Heredoc current word: "PAGER cat"
2022/05/05 12:18:04 Heredoc current word: "cf8110e8e028188d140944ad469ceb8f"
2022/05/05 12:18:04 exiting heredoc
2022/05/05 12:18:04 command: "while" [read var val; do export $var=$val; done <<cf8110e8e028188d140944ad469ceb8f LC_ALL en_US.utf8 ENV TMOUT 0 LC_CTYPE PAGER cat cf8110e8e028188d140944ad469ceb8f]
2022/05/05 12:18:04 Error: Received unexpected command while
2022/05/05 12:18:04 command: "unset" [CDPATH HISTORY MAIL MAILCHECK MAILPATH autocorrect correct]
2022/05/05 12:18:04 Error: Received unexpected command unset
2022/05/05 12:18:04 command: "test" [-e / 2>/dev/null; echo tramp_exit_status $?]
2022/05/05 12:18:04 command: "/bin/test" [-e / 2>/dev/null; echo tramp_exit_status $?]
2022/05/05 12:18:04 Error: Received unexpected command /bin/test
2022/05/05 12:18:04 command: "/usr/bin/test" [-e / 2>/dev/null; echo tramp_exit_status $?]
2022/05/05 12:18:04 Error: Received unexpected command /usr/bin/test
2022/05/05 12:18:04 Heredoc current word: "'cf8110e8e028188d140944ad469ceb8f'"
2022/05/05 12:18:04 Encountered heredoc marker: 'cf8110e8e028188d140944ad469ceb8f'
2022/05/05 12:18:04 Heredoc current word: "/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/bin"
2022/05/05 12:18:04 Heredoc current word: "/sbin"
2022/05/05 12:18:04 Heredoc current word: "/usr/sbin"
2022/05/05 12:18:04 Heredoc current word: "/usr/local/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/local/sbin"
2022/05/05 12:18:04 Heredoc current word: "/local/bin"
2022/05/05 12:18:04 Heredoc current word: "/local/freeware/bin"
2022/05/05 12:18:04 Heredoc current word: "/local/gnu/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/freeware/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/pkg/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/contrib/bin"
2022/05/05 12:18:04 Heredoc current word: "/opt/bin"
2022/05/05 12:18:04 Heredoc current word: "/opt/sbin"
2022/05/05 12:18:04 Heredoc current word: "/opt/local/bin"
2022/05/05 12:18:04 Heredoc current word: "cf8110e8e028188d140944ad469ceb8f"
2022/05/05 12:18:04 exiting heredoc
2022/05/05 12:18:04 command: "while" [read d; do if test -x $d/ls && test -f $d/ls; then echo tramp_executable $d/ls; break; fi; done <<cf8110e8e028188d140944ad469ceb8f /bin /usr/bin /sbin /usr/sbin /usr/local/bin /usr/local/sbin /local/bin /local/freeware/bin /local/gnu/bin /usr/freeware/bin /usr/pkg/bin /usr/contrib/bin /opt/bin /opt/sbin /opt/local/bin cf8110e8e028188d140944ad469ceb8f]
2022/05/05 12:18:04 Error: Received unexpected command while
2022/05/05 12:18:04 Heredoc current word: "'cf8110e8e028188d140944ad469ceb8f'"
2022/05/05 12:18:04 Encountered heredoc marker: 'cf8110e8e028188d140944ad469ceb8f'
2022/05/05 12:18:04 Heredoc current word: "/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/bin"
2022/05/05 12:18:04 Heredoc current word: "/sbin"
2022/05/05 12:18:04 Heredoc current word: "/usr/sbin"
2022/05/05 12:18:04 Heredoc current word: "/usr/local/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/local/sbin"
2022/05/05 12:18:04 Heredoc current word: "/local/bin"
2022/05/05 12:18:04 Heredoc current word: "/local/freeware/bin"
2022/05/05 12:18:04 Heredoc current word: "/local/gnu/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/freeware/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/pkg/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/contrib/bin"
2022/05/05 12:18:04 Heredoc current word: "/opt/bin"
2022/05/05 12:18:04 Heredoc current word: "/opt/sbin"
2022/05/05 12:18:04 Heredoc current word: "/opt/local/bin"
2022/05/05 12:18:04 Heredoc current word: "cf8110e8e028188d140944ad469ceb8f"
2022/05/05 12:18:04 exiting heredoc
2022/05/05 12:18:04 command: "while" [read d; do if test -x $d/gnuls && test -f $d/gnuls; then echo tramp_executable $d/gnuls; break; fi; done <<cf8110e8e028188d140944ad469ceb8f /bin /usr/bin /sbin /usr/sbin /usr/local/bin /usr/local/sbin /local/bin /local/freeware/bin /local/gnu/bin /usr/freeware/bin /usr/pkg/bin /usr/contrib/bin /opt/bin /opt/sbin /opt/local/bin cf8110e8e028188d140944ad469ceb8f]
2022/05/05 12:18:04 Error: Received unexpected command while
2022/05/05 12:18:04 Heredoc current word: "'cf8110e8e028188d140944ad469ceb8f'"
2022/05/05 12:18:04 Encountered heredoc marker: 'cf8110e8e028188d140944ad469ceb8f'
2022/05/05 12:18:04 Heredoc current word: "/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/bin"
2022/05/05 12:18:04 Heredoc current word: "/sbin"
2022/05/05 12:18:04 Heredoc current word: "/usr/sbin"
2022/05/05 12:18:04 Heredoc current word: "/usr/local/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/local/sbin"
2022/05/05 12:18:04 Heredoc current word: "/local/bin"
2022/05/05 12:18:04 Heredoc current word: "/local/freeware/bin"
2022/05/05 12:18:04 Heredoc current word: "/local/gnu/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/freeware/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/pkg/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/contrib/bin"
2022/05/05 12:18:04 Heredoc current word: "/opt/bin"
2022/05/05 12:18:04 Heredoc current word: "/opt/sbin"
2022/05/05 12:18:04 Heredoc current word: "/opt/local/bin"
2022/05/05 12:18:04 Heredoc current word: "cf8110e8e028188d140944ad469ceb8f"
2022/05/05 12:18:04 exiting heredoc
2022/05/05 12:18:04 command: "while" [read d; do if test -x $d/gls && test -f $d/gls; then echo tramp_executable $d/gls; break; fi; done <<cf8110e8e028188d140944ad469ceb8f /bin /usr/bin /sbin /usr/sbin /usr/local/bin /usr/local/sbin /local/bin /local/freeware/bin /local/gnu/bin /usr/freeware/bin /usr/pkg/bin /usr/contrib/bin /opt/bin /opt/sbin /opt/local/bin cf8110e8e028188d140944ad469ceb8f]
2022/05/05 12:18:04 Error: Received unexpected command while
2022/05/05 12:18:04 command: "test" [-e / 2>/dev/null; echo tramp_exit_status $?]
2022/05/05 12:18:04 command: "/bin/test" [-e / 2>/dev/null; echo tramp_exit_status $?]
2022/05/05 12:18:04 Error: Received unexpected command /bin/test
2022/05/05 12:18:04 command: "/usr/bin/test" [-e / 2>/dev/null; echo tramp_exit_status $?]
2022/05/05 12:18:04 Error: Received unexpected command /usr/bin/test
2022/05/05 12:18:04 Heredoc current word: "'cf8110e8e028188d140944ad469ceb8f'"
2022/05/05 12:18:04 Encountered heredoc marker: 'cf8110e8e028188d140944ad469ceb8f'
2022/05/05 12:18:04 Heredoc current word: "/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/bin"
2022/05/05 12:18:04 Heredoc current word: "/sbin"
2022/05/05 12:18:04 Heredoc current word: "/usr/sbin"
2022/05/05 12:18:04 Heredoc current word: "/usr/local/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/local/sbin"
2022/05/05 12:18:04 Heredoc current word: "/local/bin"
2022/05/05 12:18:04 Heredoc current word: "/local/freeware/bin"
2022/05/05 12:18:04 Heredoc current word: "/local/gnu/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/freeware/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/pkg/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/contrib/bin"
2022/05/05 12:18:04 Heredoc current word: "/opt/bin"
2022/05/05 12:18:04 Heredoc current word: "/opt/sbin"
2022/05/05 12:18:04 Heredoc current word: "/opt/local/bin"
2022/05/05 12:18:04 Heredoc current word: "cf8110e8e028188d140944ad469ceb8f"
2022/05/05 12:18:04 exiting heredoc
2022/05/05 12:18:04 command: "while" [read d; do if test -x $d/ls && test -f $d/ls; then echo tramp_executable $d/ls; break; fi; done <<cf8110e8e028188d140944ad469ceb8f /bin /usr/bin /sbin /usr/sbin /usr/local/bin /usr/local/sbin /local/bin /local/freeware/bin /local/gnu/bin /usr/freeware/bin /usr/pkg/bin /usr/contrib/bin /opt/bin /opt/sbin /opt/local/bin cf8110e8e028188d140944ad469ceb8f]
2022/05/05 12:18:04 Error: Received unexpected command while
2022/05/05 12:18:04 Heredoc current word: "'cf8110e8e028188d140944ad469ceb8f'"
2022/05/05 12:18:04 Encountered heredoc marker: 'cf8110e8e028188d140944ad469ceb8f'
2022/05/05 12:18:04 Heredoc current word: "/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/bin"
2022/05/05 12:18:04 Heredoc current word: "/sbin"
2022/05/05 12:18:04 Heredoc current word: "/usr/sbin"
2022/05/05 12:18:04 Heredoc current word: "/usr/local/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/local/sbin"
2022/05/05 12:18:04 Heredoc current word: "/local/bin"
2022/05/05 12:18:04 Heredoc current word: "/local/freeware/bin"
2022/05/05 12:18:04 Heredoc current word: "/local/gnu/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/freeware/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/pkg/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/contrib/bin"
2022/05/05 12:18:04 Heredoc current word: "/opt/bin"
2022/05/05 12:18:04 Heredoc current word: "/opt/sbin"
2022/05/05 12:18:04 Heredoc current word: "/opt/local/bin"
2022/05/05 12:18:04 Heredoc current word: "cf8110e8e028188d140944ad469ceb8f"
2022/05/05 12:18:04 exiting heredoc
2022/05/05 12:18:04 command: "while" [read d; do if test -x $d/gnuls && test -f $d/gnuls; then echo tramp_executable $d/gnuls; break; fi; done <<cf8110e8e028188d140944ad469ceb8f /bin /usr/bin /sbin /usr/sbin /usr/local/bin /usr/local/sbin /local/bin /local/freeware/bin /local/gnu/bin /usr/freeware/bin /usr/pkg/bin /usr/contrib/bin /opt/bin /opt/sbin /opt/local/bin cf8110e8e028188d140944ad469ceb8f]
2022/05/05 12:18:04 Error: Received unexpected command while
2022/05/05 12:18:04 Heredoc current word: "'cf8110e8e028188d140944ad469ceb8f'"
2022/05/05 12:18:04 Encountered heredoc marker: 'cf8110e8e028188d140944ad469ceb8f'
2022/05/05 12:18:04 Heredoc current word: "/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/bin"
2022/05/05 12:18:04 Heredoc current word: "/sbin"
2022/05/05 12:18:04 Heredoc current word: "/usr/sbin"
2022/05/05 12:18:04 Heredoc current word: "/usr/local/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/local/sbin"
2022/05/05 12:18:04 Heredoc current word: "/local/bin"
2022/05/05 12:18:04 Heredoc current word: "/local/freeware/bin"
2022/05/05 12:18:04 Heredoc current word: "/local/gnu/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/freeware/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/pkg/bin"
2022/05/05 12:18:04 Heredoc current word: "/usr/contrib/bin"
2022/05/05 12:18:04 Heredoc current word: "/opt/bin"
2022/05/05 12:18:04 Heredoc current word: "/opt/sbin"
2022/05/05 12:18:04 Heredoc current word: "/opt/local/bin"
2022/05/05 12:18:04 Heredoc current word: "cf8110e8e028188d140944ad469ceb8f"
2022/05/05 12:18:04 exiting heredoc
2022/05/05 12:18:04 command: "while" [read d; do if test -x $d/gls && test -f $d/gls; then echo tramp_executable $d/gls; break; fi; done <<cf8110e8e028188d140944ad469ceb8f /bin /usr/bin /sbin /usr/sbin /usr/local/bin /usr/local/sbin /local/bin /local/freeware/bin /local/gnu/bin /usr/freeware/bin /usr/pkg/bin /usr/contrib/bin /opt/bin /opt/sbin /opt/local/bin cf8110e8e028188d140944ad469ceb8f]
2022/05/05 12:18:04 Error: Received unexpected command while
2022/05/05 12:18:04 command: "test" [-r /hallo 2>/dev/null; echo tramp_exit_status $?]

@ -0,0 +1,144 @@
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/binary"
"encoding/pem"
"io/ioutil"
"log"
ipfsapi "github.com/ipfs/go-ipfs-api"
"golang.org/x/crypto/ssh"
)
func generatePrivateKey(bitSize int) (*rsa.PrivateKey, error) {
// Private Key generation
privateKey, err := rsa.GenerateKey(rand.Reader, bitSize)
if err != nil {
return nil, err
}
// Validate Private Key
err = privateKey.Validate()
if err != nil {
return nil, err
}
log.Println("Private Key generated")
return privateKey, nil
}
func encodePrivateKeyToPEM(privateKey *rsa.PrivateKey) []byte {
// Get ASN.1 DER format
privDER := x509.MarshalPKCS1PrivateKey(privateKey)
// pem.Block
privBlock := pem.Block{
Type: "RSA PRIVATE KEY",
Headers: nil,
Bytes: privDER,
}
// Private key in PEM format
privatePEM := pem.EncodeToMemory(&privBlock)
return privatePEM
}
// parseDims extracts two uint32s from the provided buffer.
func parseDims(b []byte) (uint32, uint32) {
w := binary.BigEndian.Uint32(b)
h := binary.BigEndian.Uint32(b[4:])
return w, h
}
const WebDir = "/hugo-website"
func main() {
// shell := ipfsapi.NewShell("127.0.0.1:5001")
// ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(time.Hour))
// _, err := shell.KeyGen(ctx, "website-index")
// if err != nil {
// log.Fatal(err)
// }
// id, err := shell.Add(
// strings.NewReader(
// "<!DOCTYPE HTML>" +
// "<html><body><h1>heeeeeeeyaa</h1></body></html>",
// ),
// )
// if err != nil {
// log.Fatal(err)
// }
// log.Println("added file by name " + id)
// resp, err := shell.PublishWithDetails(id, "website/index.html", 24*365*10*time.Hour, time.Hour, true)
// if err != nil {
// log.Fatal(err)
// }
// log.Println(resp.Name)
// obj, err := shell.ObjectGet("QmbJSh4EQvxz6cD6NyZ92smxBYfwTU6zr6No5APjANZ92D")
// if err != nil {
// log.Fatal(err)
// }
// log.Println(obj.Links)
// err = shell.FilesMkdir(ctx, WebDir)
// if err!= nil {
// log.Fatal(err)
// }
// shell.FilesLs(ctx context.Context, path string, options ...ipfsapi.FilesOpt)
// stats, err := shell.FilesStat(ctx, WebDir)
// if err != nil {
// if ipfsErr, ok := err.(*ipfsapi.Error); ok {
// log.Println("IPFS error code: ", ipfsErr.Code, ipfsErr.Command)
// }
// log.Fatal(err)
// }
// log.Println(stats)
// Public key authentication is done by comparing
// the public key of a received connection
// with the entries in the authorized_keys file.
authorizedKeysBytes, err := ioutil.ReadFile("/home/hugo/.ssh/authorized_keys")
if err != nil {
log.Fatalf("Failed to load authorized_keys, err: %v", err)
}
authorizedKeysMap := map[string]bool{}
for len(authorizedKeysBytes) > 0 {
pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(authorizedKeysBytes)
if err != nil {
log.Fatal(err)
}
authorizedKeysMap[string(pubKey.Marshal())] = true
authorizedKeysBytes = rest
}
// shell :=
filestore, err := NewIPFSFilestore(ipfsapi.NewShell("127.0.0.1:5001"), WebDir)
if err != nil {
log.Fatal(err)
}
server := &Sshd{
AuthorizedKeysMap: authorizedKeysMap,
Filestore: filestore,
}
log.Fatal(server.Listen("0.0.0.0:2022"))
}

BIN
nssh

Binary file not shown.

@ -0,0 +1,228 @@
package main
import (
"bufio"
"errors"
"io"
"log"
"os"
"strings"
"unsafe"
"github.com/google/shlex"
"github.com/pkg/term/termios"
"golang.org/x/sys/unix"
)
type Shell struct {
pty *os.File
tty *os.File
prompt []byte
readData []byte
readIndex int
winsize *Winsize
}
type Command struct {
Name string
Arguments []string
}
func (s *Shell) GetPty() *os.File {
return s.pty
}
func (s *Shell) Attach(conn io.ReadWriteCloser) error {
pty, tty, err := termios.Pty()
if err != nil {
return err
}
s.pty = pty
s.tty = tty
if s.winsize != nil {
SetWinsize(s.pty.Fd(), s.winsize)
}
go func() {
defer s.pty.Close()
io.Copy(s.pty, conn)
}()
go func() {
defer conn.Close()
io.Copy(conn, s.pty)
}()
_, err = s.tty.Write(s.prompt)
return err
}
func NewShell(prompt string) *Shell {
return &Shell{
prompt: []byte(prompt),
}
}
func (s *Shell) SetWinsize(w, h uint32) {
s.winsize = &Winsize{Width: uint16(w), Height: uint16(h)}
if s.pty != nil {
SetWinsize(s.pty.Fd(), s.winsize)
}
}
func (s *Shell) Close() (error, error) {
return s.pty.Close(), s.tty.Close()
}
var ErrEmptyCommand error = errors.New("Empty command line")
func (s *Shell) ReadCommand() (*Command, error) {
var currentLine string
var backslash bool
var insideDoubleQuote bool
var insideSingleQuote bool
var maybeHeredoc bool
var insideHeredoc bool
var heredocMarker string
var heredocMarkerComplete bool
var heredocCurrentWord string
reader := bufio.NewReader(s.tty)
GatherCommand:
for {
char, _, err := reader.ReadRune()
if err != nil {
return nil, err
}
if insideHeredoc {
currentLine += string(char)
if !heredocMarkerComplete && char == '<' {
insideHeredoc = false
continue
}
if char == '\n' {
log.Printf("Heredoc current word: \"%s\"", heredocCurrentWord)
if heredocCurrentWord == heredocMarker {
log.Println("exiting heredoc")
insideHeredoc = false
heredocMarkerComplete = false
break GatherCommand
}
if !heredocMarkerComplete {
log.Println("Encountered heredoc marker: " + heredocCurrentWord)
heredocMarker = strings.Trim(heredocCurrentWord, "'")
heredocMarkerComplete = true
}
heredocCurrentWord = ""
continue
}
heredocCurrentWord += string(char)
continue
}
if backslash {
if !insideDoubleQuote && char == '\n' {
currentLine += string(" ")
continue
}
currentLine += "\\" + string(char)
backslash = false
continue
}
switch rune(char) {
case '<':
currentLine += string(char)
if maybeHeredoc {
maybeHeredoc = false
insideHeredoc = true
continue
}
maybeHeredoc = true
continue
case '\\':
backslash = true
continue
case '"':
insideDoubleQuote = !insideDoubleQuote
currentLine += string(char)
case '\'':
insideSingleQuote = !insideSingleQuote
currentLine += string(char)
case '\n':
if insideSingleQuote || insideDoubleQuote {
currentLine += string(char)
continue
}
break GatherCommand
default:
currentLine += string(char)
}
}
commandLine, err := shlex.Split(currentLine)
if err != nil {
return nil, err
}
if len(commandLine) == 0 {
return nil, ErrEmptyCommand
}
comm := &Command{Name: commandLine[0]}
if len(commandLine) > 1 {
comm.Arguments = commandLine[1:]
}
return comm, nil
}
func (s *Shell) SetPrompt(prompt string) {
log.Printf("Changing prompt to \"%s\"", prompt)
s.prompt = []byte(prompt)
}
func (s *Shell) WritePrompt() error {
_, err := s.tty.Write(s.prompt)
return err
}
func (s *Shell) WriteOutput(output []byte) (int, error) {
return s.tty.Write(output)
}
func (s *Shell) WriteOutputString(output string) (int, error) {
return s.WriteOutput([]byte(output))
}
// Winsize stores the Height and Width of a terminal.
type Winsize struct {
Height uint16
Width uint16
x uint16 // unused
y uint16 // unused
}
// SetWinsize sets the size of the given pty.
func SetWinsize(fd uintptr, winsize *Winsize) {
log.Printf("window resize %dx%d", winsize.Width, winsize.Height)
unix.Syscall(
unix.SYS_IOCTL,
fd,
uintptr(unix.TIOCSWINSZ), uintptr(unsafe.Pointer(winsize)),
)
}

@ -0,0 +1 @@
package main

@ -0,0 +1,170 @@
package main
import (
"errors"
"fmt"
"io"
"log"
"net"
"golang.org/x/crypto/ssh"
)
type Sshd struct {
AuthorizedKeysMap map[string]bool
Filestore Filestore
}
func (s *Sshd) Listen(iface string) error {
// An SSH server is represented by a ServerConfig, which holds
// certificate details and handles authentication of ServerConns.
config := &ssh.ServerConfig{
// Remove to disable public key auth.
PublicKeyCallback: func(c ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
if s.AuthorizedKeysMap[string(pubKey.Marshal())] {
return &ssh.Permissions{
// Record the public key used for authentication.
Extensions: map[string]string{
"pubkey-fp": ssh.FingerprintSHA256(pubKey),
},
}, nil
}
return nil, fmt.Errorf("unknown public key for %q", c.User())
},
}
bitSize := 4096
privateKey, err := generatePrivateKey(bitSize)
if err != nil {
return err
}
privateBytes := encodePrivateKeyToPEM(privateKey)
private, err := ssh.ParsePrivateKey(privateBytes)
if err != nil {
return fmt.Errorf("Failed to parse private key: %w", err)
}
config.AddHostKey(private)
// Once a ServerConfig has been configured, connections can be
// accepted.
listener, err := net.Listen("tcp", iface)
if err != nil {
return err
}
return s.HandleRequests(listener, config)
}
func (s *Sshd) HandleRequests(listener net.Listener, config *ssh.ServerConfig) error {
for {
nConn, err := listener.Accept()
if err != nil {
return fmt.Errorf("failed to accept incoming connection: %w", err)
}
// Before use, a handshake must be performed on the incoming
// net.Conn.
conn, chans, reqs, err := ssh.NewServerConn(nConn, config)
if err != nil {
log.Printf("failed to handshake: %s", err)
continue
}
log.Printf("logged in with key %s", conn.Permissions.Extensions["pubkey-fp"])
// The incoming Request channel must be serviced.
go ssh.DiscardRequests(reqs)
// Service the incoming Channel channel.
for newChannel := range chans {
// Channels have a type, depending on the application level
// protocol intended. In the case of a shell, the type is
// "session" and ServerShell may be used to present a simple
// terminal interface.
if newChannel.ChannelType() != "session" {
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
continue
}
channel, requests, err := newChannel.Accept()
if err != nil {
return fmt.Errorf("Could not accept channel: %w", err)
}
session := &SshSession{
shell: NewShell("user@host:/# "),
filestore: s.Filestore,
}
// Sessions have out-of-band requests such as "shell",
// "pty-req" and "env". Here we handle only the
// "shell" request.
go session.HandleRequests(requests)
go session.RunShell(channel)
}
}
}
type SshSession struct {
shell *Shell
filestore Filestore
}
func (s *SshSession) HandleRequests(in <-chan *ssh.Request) {
for req := range in {
log.Printf("received request of type \"%s\"", req.Type)
var ok bool
switch req.Type {
case "shell":
ok = true
case "pty-req":
// Responding 'ok' here will let the client
// know we have a pty ready for input
ok = true
// Parse body...
termLen := req.Payload[3]
termEnv := string(req.Payload[4 : termLen+4])
w, h := parseDims(req.Payload[termLen+4:])
s.shell.SetWinsize(w, h)
log.Printf("pty-req '%s'", termEnv)
}
req.Reply(ok, nil)
}
}
func (s *SshSession) RunShell(channel io.ReadWriteCloser) {
s.shell.Attach(channel)
handler := NewCommandHandler(s.shell, s.filestore)
go func() {
for {
comm, err := s.shell.ReadCommand()
if err != nil {
if errors.Is(err, io.EOF) {
log.Println("Received EOF, closing TTY")
} else {
log.Println("Error reading command: ", err)
}
if !errors.Is(err, ErrEmptyCommand) {
s.shell.Close()
return
}
} else {
log.Printf("command: \"%s\" %s", comm.Name, comm.Arguments)
handler.Handle(comm)
}
err = s.shell.WritePrompt()
if err != nil {
log.Println(err)
}
}
}()
}
Loading…
Cancel
Save