diff --git a/go.mod b/go.mod index 9bf1f81dc..7169dcdc2 100644 --- a/go.mod +++ b/go.mod @@ -23,6 +23,8 @@ require ( github.com/jlaffaye/ftp v0.0.0-20190126081051-8019e6774408 github.com/jtolds/gls v4.2.1+incompatible // indirect github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 // indirect + github.com/koofr/go-httpclient v0.0.0-20180104120329-03786175608a // indirect + github.com/koofr/go-koofrclient v0.0.0-20190131164641-7f327592caff github.com/kr/fs v0.1.0 // indirect github.com/mattn/go-runewidth v0.0.4 // indirect github.com/ncw/go-acd v0.0.0-20171120105400-887eb06ab6a2 diff --git a/go.sum b/go.sum index 8ee801a44..1e0072fe1 100644 --- a/go.sum +++ b/go.sum @@ -87,6 +87,10 @@ github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVY github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro= github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/koofr/go-httpclient v0.0.0-20180104120329-03786175608a h1:W+gnfphB7WpRj0rbTF40e3edULfri4fou2kUFw6AF3A= +github.com/koofr/go-httpclient v0.0.0-20180104120329-03786175608a/go.mod h1:3xszwh+rNrYk1r9SStc4iJ326gne1OaBcrdB1ACsbzI= +github.com/koofr/go-koofrclient v0.0.0-20190131164641-7f327592caff h1:GlfzG8bgyoJYz+5sMvGpYnHrg4veNVNnDGuE9hTEMHk= +github.com/koofr/go-koofrclient v0.0.0-20190131164641-7f327592caff/go.mod h1:MRAz4Gsxd+OzrZ0owwrUHc0zLESL+1Y5syqK/sJxK2A= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= diff --git a/vendor/github.com/koofr/go-httpclient/.gitignore b/vendor/github.com/koofr/go-httpclient/.gitignore new file mode 100644 index 000000000..14d43dbf3 --- /dev/null +++ b/vendor/github.com/koofr/go-httpclient/.gitignore @@ -0,0 +1,11 @@ +/bin +/pkg + +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# developer specific +*.sublime-workspace +*.sublime-project diff --git a/vendor/github.com/koofr/go-httpclient/LICENSE b/vendor/github.com/koofr/go-httpclient/LICENSE new file mode 100644 index 000000000..309e3042a --- /dev/null +++ b/vendor/github.com/koofr/go-httpclient/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Koofr + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/koofr/go-httpclient/README.md b/vendor/github.com/koofr/go-httpclient/README.md new file mode 100644 index 000000000..96e66442e --- /dev/null +++ b/vendor/github.com/koofr/go-httpclient/README.md @@ -0,0 +1,15 @@ +go-httpclient +============= + +Go HTTP client. + +[![GoDoc](https://godoc.org/github.com/koofr/go-httpclient?status.png)](https://godoc.org/github.com/koofr/go-httpclient) + +## Install + + go get github.com/koofr/go-httpclient + +## Testing + + go get -t + go test diff --git a/vendor/github.com/koofr/go-httpclient/errors.go b/vendor/github.com/koofr/go-httpclient/errors.go new file mode 100644 index 000000000..c79e304d8 --- /dev/null +++ b/vendor/github.com/koofr/go-httpclient/errors.go @@ -0,0 +1,38 @@ +package httpclient + +import ( + "errors" + "fmt" + "net/http" +) + +type InvalidStatusError struct { + Expected []int + Got int + Headers http.Header + Content string +} + +func (e InvalidStatusError) Error() string { + return fmt.Sprintf("Invalid response status! Got %d, expected %d; headers: %s, content: %s", e.Got, e.Expected, e.Headers, e.Content) +} + +func IsInvalidStatusError(err error) (invalidStatusError *InvalidStatusError, ok bool) { + if ise, ok := err.(InvalidStatusError); ok { + return &ise, true + } else if ise, ok := err.(*InvalidStatusError); ok { + return ise, true + } else { + return nil, false + } +} + +func IsInvalidStatusCode(err error, statusCode int) bool { + if ise, ok := IsInvalidStatusError(err); ok { + return ise.Got == statusCode + } else { + return false + } +} + +var RateLimitTimeoutError = errors.New("HTTPClient rate limit timeout") diff --git a/vendor/github.com/koofr/go-httpclient/httpclient.go b/vendor/github.com/koofr/go-httpclient/httpclient.go new file mode 100644 index 000000000..2226af358 --- /dev/null +++ b/vendor/github.com/koofr/go-httpclient/httpclient.go @@ -0,0 +1,351 @@ +package httpclient + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/http/httputil" + "net/url" + "os" + "strings" + "time" +) + +var XmlHeaderBytes []byte = []byte(xml.Header) + +type HTTPClient struct { + BaseURL *url.URL + Headers http.Header + Client *http.Client + PostHooks map[int]func(*http.Request, *http.Response) error + rateLimited bool + rateLimitChan chan struct{} + rateLimitTimeout time.Duration +} + +func New() (httpClient *HTTPClient) { + return &HTTPClient{ + Client: HttpClient, + Headers: make(http.Header), + PostHooks: make(map[int]func(*http.Request, *http.Response) error), + } +} + +func Insecure() (httpClient *HTTPClient) { + httpClient = New() + httpClient.Client = InsecureHttpClient + return httpClient +} + +var DefaultClient = New() + +func (c *HTTPClient) SetPostHook(onStatus int, hook func(*http.Request, *http.Response) error) { + c.PostHooks[onStatus] = hook +} + +func (c *HTTPClient) SetRateLimit(limit int, timeout time.Duration) { + c.rateLimited = true + c.rateLimitChan = make(chan struct{}, limit) + + for i := 0; i < limit; i++ { + c.rateLimitChan <- struct{}{} + } + + c.rateLimitTimeout = timeout +} + +func (c *HTTPClient) buildURL(req *RequestData) *url.URL { + bu := c.BaseURL + + rpath := req.Path + + if strings.HasSuffix(bu.Path, "/") && strings.HasPrefix(rpath, "/") { + rpath = rpath[1:] + } + + opaque := EscapePath(bu.Path + rpath) + + u := &url.URL{ + Scheme: bu.Scheme, + Host: bu.Host, + Opaque: opaque, + } + + if req.Params != nil { + u.RawQuery = req.Params.Encode() + } + + return u +} + +func (c *HTTPClient) setHeaders(req *RequestData, httpReq *http.Request) { + switch req.RespEncoding { + case EncodingJSON: + httpReq.Header.Set("Accept", "application/json") + case EncodingXML: + httpReq.Header.Set("Accept", "application/xml") + } + + if c.Headers != nil { + for key, values := range c.Headers { + for _, value := range values { + httpReq.Header.Set(key, value) + } + } + } + + if req.Headers != nil { + for key, values := range req.Headers { + for _, value := range values { + httpReq.Header.Set(key, value) + } + } + } +} + +func (c *HTTPClient) checkStatus(req *RequestData, response *http.Response) (err error) { + if req.ExpectedStatus != nil { + statusOk := false + + for _, status := range req.ExpectedStatus { + if response.StatusCode == status { + statusOk = true + } + } + + if !statusOk { + lr := io.LimitReader(response.Body, 10*1024) + contentBytes, _ := ioutil.ReadAll(lr) + content := string(contentBytes) + + err = InvalidStatusError{ + Expected: req.ExpectedStatus, + Got: response.StatusCode, + Headers: response.Header, + Content: content, + } + + return err + } + } + + return nil +} + +func (c *HTTPClient) unmarshalResponse(req *RequestData, response *http.Response) (err error) { + var buf []byte + + switch req.RespEncoding { + case EncodingJSON: + defer response.Body.Close() + + if buf, err = ioutil.ReadAll(response.Body); err != nil { + return err + } + + err = json.Unmarshal(buf, req.RespValue) + + if err != nil { + return err + } + + return nil + + case EncodingXML: + defer response.Body.Close() + + if buf, err = ioutil.ReadAll(response.Body); err != nil { + return err + } + + err = xml.Unmarshal(buf, req.RespValue) + + if err != nil { + return err + } + + return nil + } + + switch req.RespValue.(type) { + case *[]byte: + defer response.Body.Close() + + if buf, err = ioutil.ReadAll(response.Body); err != nil { + return err + } + + respVal := req.RespValue.(*[]byte) + *respVal = buf + + return nil + } + + if req.RespConsume { + defer response.Body.Close() + ioutil.ReadAll(response.Body) + } + + return nil +} + +func (c *HTTPClient) marshalRequest(req *RequestData) (err error) { + if req.ReqReader != nil || req.ReqValue == nil { + return nil + } + + if req.Headers == nil { + req.Headers = make(http.Header) + } + + var buf []byte + + switch req.ReqEncoding { + case EncodingJSON: + buf, err = json.Marshal(req.ReqValue) + + if err != nil { + return err + } + + req.ReqReader = bytes.NewReader(buf) + req.Headers.Set("Content-Type", "application/json") + req.Headers.Set("Content-Length", fmt.Sprintf("%d", len(buf))) + + req.ReqContentLength = int64(len(buf)) + + return nil + + case EncodingXML: + buf, err = xml.Marshal(req.ReqValue) + + if err != nil { + return err + } + + buf = append(XmlHeaderBytes, buf...) + + req.ReqReader = bytes.NewReader(buf) + req.Headers.Set("Content-Type", "application/xml") + req.Headers.Set("Content-Length", fmt.Sprintf("%d", len(buf))) + + req.ReqContentLength = int64(len(buf)) + + return nil + + case EncodingForm: + if data, ok := req.ReqValue.(url.Values); ok { + formStr := data.Encode() + req.ReqReader = strings.NewReader(formStr) + req.Headers.Set("Content-Type", "application/x-www-form-urlencoded") + + req.Headers.Set("Content-Length", fmt.Sprintf("%d", len(formStr))) + + req.ReqContentLength = int64(len(formStr)) + + return nil + } else { + return fmt.Errorf("HTTPClient: invalid ReqValue type %T", req.ReqValue) + } + } + + return fmt.Errorf("HTTPClient: invalid ReqEncoding: %s", req.ReqEncoding) +} + +func (c *HTTPClient) runPostHook(req *http.Request, response *http.Response) (err error) { + hook, ok := c.PostHooks[response.StatusCode] + + if ok { + err = hook(req, response) + } + + return err +} + +func (c *HTTPClient) Request(req *RequestData) (response *http.Response, err error) { + err = c.marshalRequest(req) + + if err != nil { + return nil, err + } + + r, err := http.NewRequest(req.Method, req.FullURL, req.ReqReader) + + if err != nil { + return nil, err + } + + r.ContentLength = req.ReqContentLength + + if req.FullURL == "" { + r.URL = c.buildURL(req) + r.Host = r.URL.Host + } + + c.setHeaders(req, r) + + if c.rateLimited { + if c.rateLimitTimeout > 0 { + select { + case t := <-c.rateLimitChan: + defer func() { + c.rateLimitChan <- t + }() + case <-time.After(c.rateLimitTimeout): + return nil, RateLimitTimeoutError + } + } else { + t := <-c.rateLimitChan + defer func() { + c.rateLimitChan <- t + }() + } + } + + isTraceEnabled := os.Getenv("HTTPCLIENT_TRACE") != "" + + if isTraceEnabled { + requestBytes, _ := httputil.DumpRequestOut(r, true) + fmt.Println(string(requestBytes)) + } + + if req.IgnoreRedirects { + transport := c.Client.Transport + + if transport == nil { + transport = http.DefaultTransport + } + + response, err = transport.RoundTrip(r) + } else { + response, err = c.Client.Do(r) + } + + if isTraceEnabled { + responseBytes, _ := httputil.DumpResponse(response, true) + fmt.Println(string(responseBytes)) + } + + if err != nil { + return response, err + } + + if err = c.runPostHook(r, response); err != nil { + return response, err + } + + if err = c.checkStatus(req, response); err != nil { + defer response.Body.Close() + return response, err + } + + if err = c.unmarshalResponse(req, response); err != nil { + return response, err + } + + return response, nil +} diff --git a/vendor/github.com/koofr/go-httpclient/requestdata.go b/vendor/github.com/koofr/go-httpclient/requestdata.go new file mode 100644 index 000000000..bfa3c784e --- /dev/null +++ b/vendor/github.com/koofr/go-httpclient/requestdata.go @@ -0,0 +1,96 @@ +package httpclient + +import ( + "io" + "net/http" + "net/url" +) + +type Encoding string + +const ( + EncodingJSON = "JSON" + EncodingXML = "XML" + EncodingForm = "Form" +) + +type RequestData struct { + Method string + Path string + Params url.Values + FullURL string // client.BaseURL + Path or FullURL + Headers http.Header + ReqReader io.Reader + ReqEncoding Encoding + ReqValue interface{} + ReqContentLength int64 + ExpectedStatus []int + IgnoreRedirects bool + RespEncoding Encoding + RespValue interface{} + RespConsume bool +} + +func (r *RequestData) CanCopy() bool { + if r.ReqReader != nil { + return false + } + + return true +} + +func (r *RequestData) Copy() (ok bool, nr *RequestData) { + if !r.CanCopy() { + return false, nil + } + + nr = &RequestData{ + Method: r.Method, + Path: r.Path, + FullURL: r.FullURL, + ReqEncoding: r.ReqEncoding, + ReqValue: r.ReqValue, + IgnoreRedirects: r.IgnoreRedirects, + RespEncoding: r.RespEncoding, + RespValue: r.RespValue, + RespConsume: r.RespConsume, + } + + if r.Params != nil { + nr.Params = make(url.Values) + + for k, vs := range r.Params { + nvs := make([]string, len(vs)) + + for i, v := range vs { + nvs[i] = v + } + + nr.Params[k] = nvs + } + } + + if r.Headers != nil { + nr.Headers = make(http.Header) + + for k, vs := range r.Headers { + nvs := make([]string, len(vs)) + + for i, v := range vs { + nvs[i] = v + } + + nr.Headers[k] = nvs + } + } + + if r.ExpectedStatus != nil { + nr.ExpectedStatus = make([]int, len(r.ExpectedStatus)) + + for i, v := range r.ExpectedStatus { + nr.ExpectedStatus[i] = v + } + } + + return true, nr +} diff --git a/vendor/github.com/koofr/go-httpclient/requestdata_upload.go b/vendor/github.com/koofr/go-httpclient/requestdata_upload.go new file mode 100644 index 000000000..da44e1775 --- /dev/null +++ b/vendor/github.com/koofr/go-httpclient/requestdata_upload.go @@ -0,0 +1,62 @@ +package httpclient + +import ( + "io" + "mime/multipart" + "net/http" +) + +func (req *RequestData) UploadFile(fieldName string, fileName string, reader io.Reader) (err error) { + return req.UploadFileExtra(fieldName, fileName, reader, nil) +} + +func (req *RequestData) UploadFileExtra(fieldName string, fileName string, reader io.Reader, extra map[string]string) (err error) { + r, w := io.Pipe() + + writer := multipart.NewWriter(w) + + go func() { + var err error + + defer func() { + if err == nil { + w.Close() + } + }() + + for k, v := range extra { + err = writer.WriteField(k, v) + + if err != nil { + w.CloseWithError(err) + return + } + } + + part, err := writer.CreateFormFile(fieldName, fileName) + + if err != nil { + w.CloseWithError(err) + return + } + + defer writer.Close() + + _, err = io.Copy(part, reader) + + if err != nil { + w.CloseWithError(err) + return + } + }() + + req.ReqReader = r + + if req.Headers == nil { + req.Headers = make(http.Header) + } + + req.Headers.Set("Content-Type", writer.FormDataContentType()) + + return +} diff --git a/vendor/github.com/koofr/go-httpclient/transport.go b/vendor/github.com/koofr/go-httpclient/transport.go new file mode 100644 index 000000000..f01e7c1ff --- /dev/null +++ b/vendor/github.com/koofr/go-httpclient/transport.go @@ -0,0 +1,29 @@ +package httpclient + +import ( + "crypto/tls" + "net/http" +) + +var HttpTransport = &http.Transport{ + DisableCompression: true, + Proxy: http.ProxyFromEnvironment, +} + +var HttpClient = &http.Client{ + Transport: HttpTransport, +} + +var InsecureTlsConfig = &tls.Config{ + InsecureSkipVerify: true, +} + +var InsecureHttpTransport = &http.Transport{ + TLSClientConfig: InsecureTlsConfig, + DisableCompression: true, + Proxy: http.ProxyFromEnvironment, +} + +var InsecureHttpClient = &http.Client{ + Transport: InsecureHttpTransport, +} diff --git a/vendor/github.com/koofr/go-httpclient/utils.go b/vendor/github.com/koofr/go-httpclient/utils.go new file mode 100644 index 000000000..59b10a718 --- /dev/null +++ b/vendor/github.com/koofr/go-httpclient/utils.go @@ -0,0 +1,14 @@ +package httpclient + +import ( + "net/url" + "strings" +) + +func EscapePath(path string) string { + u := url.URL{ + Path: path, + } + + return strings.Replace(u.String(), "+", "%2b", -1) +} diff --git a/vendor/github.com/koofr/go-koofrclient/.gitignore b/vendor/github.com/koofr/go-koofrclient/.gitignore new file mode 100644 index 000000000..14d43dbf3 --- /dev/null +++ b/vendor/github.com/koofr/go-koofrclient/.gitignore @@ -0,0 +1,11 @@ +/bin +/pkg + +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# developer specific +*.sublime-workspace +*.sublime-project diff --git a/vendor/github.com/koofr/go-koofrclient/LICENSE b/vendor/github.com/koofr/go-koofrclient/LICENSE new file mode 100644 index 000000000..309e3042a --- /dev/null +++ b/vendor/github.com/koofr/go-koofrclient/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Koofr + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/koofr/go-koofrclient/README.md b/vendor/github.com/koofr/go-koofrclient/README.md new file mode 100644 index 000000000..baa537e90 --- /dev/null +++ b/vendor/github.com/koofr/go-koofrclient/README.md @@ -0,0 +1,15 @@ +go-koofrclient +=========== + +Go Koofr client. + +[![GoDoc](https://godoc.org/github.com/koofr/go-koofrclient?status.png)](https://godoc.org/github.com/koofr/go-koofrclient) + +## Install + + go get github.com/koofr/go-koofrclient + +## Testing + + go get -t + KOOFR_APIBASE="https://app.koofr.net" KOOFR_EMAIL="email@example.com" KOOFR_PASSWORD="yourpassword" go test diff --git a/vendor/github.com/koofr/go-koofrclient/api_scheme.go b/vendor/github.com/koofr/go-koofrclient/api_scheme.go new file mode 100644 index 000000000..78e75b050 --- /dev/null +++ b/vendor/github.com/koofr/go-koofrclient/api_scheme.go @@ -0,0 +1,217 @@ +package koofrclient + +import ( + "path" +) + +type TokenRequest struct { + Email string `json:"email"` + Password string `json:"password"` +} + +type Token struct { + Token string +} + +type MountType string + +const ( + MountDeviceType = "device" + MountExportType = "export" + MountImportType = "import" +) + +type Mount struct { + Id string `json:"id"` + Name string `json:"name"` + Type MountType `json:"type"` + Origin string `json:"origin"` + SpaceTotal int64 `json:"spaceTotal"` + SpaceUsed int64 `json:"spaceUsed"` + Online bool `json:"online"` + Owner MountUser `json:"owner"` + Users []MountUser `json:"users"` + Groups []MountGroup `json:"groups"` + Version int `json:"version"` + Permissions MountPermissions `json:"permissions"` + IsPrimary bool `json:"isPrimary"` + IsShared bool `json:"isShared"` +} + +type MountUser struct { + Id string `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Permissions MountPermissions `json:"permissions"` +} + +type MountGroup struct { + Id string `json:"id"` + Name string `json:"name"` + Permissions MountPermissions `json:"permissions"` +} + +type MountPermissions struct { + Read bool `json:"READ"` + Write bool `json:"write"` + Owner bool `json:"OWNER"` + Mount bool `json:"MOUNT"` + CreateReceiver bool `json:"CREATE_RECEIVER"` + CreateLink bool `json:"CREATE_LINK"` + CreateAction bool `json:"CREATE_ACTION"` + Comment bool `json:"COMMENT"` +} + +type DeviceProvider string + +const ( + StorageHubProvider = "storagehub" + StorageBlobProvider = "storageblob" +) + +type Device struct { + Id string `json:"id"` + ApiKey string `json:"apiKey"` + Name string `json:"name"` + Status string `json:"status"` + SpaceTotal int64 `json:"spaceTotal"` + SpaceUsed int64 `json:"spaceUsed"` + SpaceFree int64 `json:"spaceFree"` + Version int `json:"version"` + Provider struct { + Name string `json:"name"` + Data interface{} `json:"data"` + } `json:"provider"` + ReadOnly bool `json:"readonly"` + RootMountId string `json:"rootMountId"` +} + +type DeviceCreate struct { + Name string `json:"name"` + ProviderName DeviceProvider `json:"providerName"` +} + +type DeviceUpdate struct { + Name string `json:"name"` +} + +type FolderCreate struct { + Name string `json:"name"` +} + +type FileCopy struct { + ToMountId string `json:"toMountId"` + TPath string `json:"toPath"` +} + +type FileMove struct { + ToMountId string `json:"toMountId"` + TPath string `json:"toPath"` +} + +type FileSpan struct { + Start int64 + End int64 +} + +type FileUpload struct { + Name string `json:"name"` +} + +type PutFilter struct { + Modified *int64 + Size *int64 + Hash *string + IgnoreNonExisting bool + NoRename bool + ForceOverwrite bool +} + +type DeleteFilter struct { + Modified *int64 + Size *int64 + Hash *string + IfEmpty bool +} + +type FileInfo struct { + Name string `json:"name"` + Type string `json:"type"` + Modified int64 `json:"modified"` + Size int64 `json:"size"` + ContentType string `json:"contentType"` + Path string `json:"path"` + Hash string `json:"hash"` +} + +type FileTree struct { + FileInfo + Children []*FileTree `json:"children"` +} + +func (tree *FileTree) Flatten() []FileInfo { + trees := []*FileTree{tree} + for i := 0; i < len(trees); i++ { + tree := trees[i] + for _, child := range tree.Children { + child.Name = path.Join(tree.Name, child.Name) + trees = append(trees, child) + } + } + infos := make([]FileInfo, len(trees)) + for i, tree := range trees { + infos[i] = tree.FileInfo + } + return infos +} + +type User struct { + Id string `json:"id"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + Email string `json:"email"` +} + +type Shared struct { + Name string `json:name` + Type MountType `json:type` + Modified int64 `json:modified` + Size int64 `json:size` + ContentType string `json:contentType` + Hash string `json:hash` + Mount Mount `json:mount` + Link Link `json:link` + Receiver Receiver `json:receiver` +} + +type Link struct { + Id string `json:id` + Name string `json:name` + Path string `json:path` + Counter int64 `json:counter` + Url string `json:url` + ShortUrl string `json:shortUrl` + Hash string `json:hash` + Host string `json:host` + HasPassword bool `json:hasPassword` + Password string `json:password` + ValidFrom int64 `json:validFrom` + ValidTo int64 `json:validTo` + PasswordRequired bool `json:passwordRequired` +} + +type Receiver struct { + Id string `json:id` + Name string `json:name` + Path string `json:path` + Counter int64 `json:counter` + Url string `json:url` + ShortUrl string `json:shortUrl` + Hash string `json:hash` + Host string `json:host` + HasPassword bool `json:hasPassword` + Password string `json:password` + ValidFrom int64 `json:validFrom` + ValidTo int64 `json:validTo` + Alert bool `json:alert` +} diff --git a/vendor/github.com/koofr/go-koofrclient/client.go b/vendor/github.com/koofr/go-koofrclient/client.go new file mode 100644 index 000000000..2821ae0d6 --- /dev/null +++ b/vendor/github.com/koofr/go-koofrclient/client.go @@ -0,0 +1,89 @@ +package koofrclient + +import ( + "fmt" + "net/http" + "net/url" + + "github.com/koofr/go-httpclient" +) + +type KoofrClient struct { + *httpclient.HTTPClient + token string + userID string +} + +func NewKoofrClient(baseUrl string, disableSecurity bool) *KoofrClient { + var httpClient *httpclient.HTTPClient + + if disableSecurity { + httpClient = httpclient.Insecure() + } else { + httpClient = httpclient.New() + } + + apiBaseUrl, _ := url.Parse(baseUrl) + + httpClient.BaseURL = apiBaseUrl + + httpClient.Headers.Set("User-Agent", "go koofrclient") + + return &KoofrClient{ + HTTPClient: httpClient, + token: "", + userID: "", + } +} + +func (c *KoofrClient) SetUserAgent(ua string) { + c.Headers.Set("User-Agent", ua) +} + +func (c *KoofrClient) SetToken(token string) { + c.token = token + c.HTTPClient.Headers.Set("Authorization", fmt.Sprintf("Token token=%s", token)) +} + +func (c *KoofrClient) GetToken() string { + return c.token +} + +func (c *KoofrClient) SetUserID(userID string) { + c.userID = userID +} + +func (c *KoofrClient) GetUserID() string { + return c.userID +} + +func (c *KoofrClient) Authenticate(email string, password string) (err error) { + var tokenResponse Token + + tokenRequest := TokenRequest{ + Email: email, + Password: password, + } + + request := httpclient.RequestData{ + Method: "POST", + Path: "/token", + Headers: make(http.Header), + ExpectedStatus: []int{http.StatusOK}, + ReqEncoding: httpclient.EncodingJSON, + ReqValue: tokenRequest, + RespEncoding: httpclient.EncodingJSON, + RespValue: &tokenResponse, + } + + res, err := c.Request(&request) + + if err != nil { + return + } + + c.SetToken(tokenResponse.Token) + c.SetUserID(res.Header.Get("X-User-ID")) + + return +} diff --git a/vendor/github.com/koofr/go-koofrclient/client_device.go b/vendor/github.com/koofr/go-koofrclient/client_device.go new file mode 100644 index 000000000..0f2390ddd --- /dev/null +++ b/vendor/github.com/koofr/go-koofrclient/client_device.go @@ -0,0 +1,84 @@ +package koofrclient + +import ( + "github.com/koofr/go-httpclient" + "net/http" +) + +func (c *KoofrClient) Devices() (devices []Device, err error) { + d := &struct { + Devices *[]Device + }{&devices} + + request := httpclient.RequestData{ + Method: "GET", + Path: "/api/v2/devices", + ExpectedStatus: []int{http.StatusOK}, + RespEncoding: httpclient.EncodingJSON, + RespValue: &d, + } + + _, err = c.Request(&request) + + return +} + +func (c *KoofrClient) DevicesCreate(name string, provider DeviceProvider) (device Device, err error) { + deviceCreate := DeviceCreate{name, provider} + + request := httpclient.RequestData{ + Method: "POST", + Path: "/api/v2/devices", + ExpectedStatus: []int{http.StatusCreated}, + ReqEncoding: httpclient.EncodingJSON, + ReqValue: deviceCreate, + RespEncoding: httpclient.EncodingJSON, + RespValue: &device, + } + + _, err = c.Request(&request) + + return +} + +func (c *KoofrClient) DevicesDetails(deviceId string) (device Device, err error) { + request := httpclient.RequestData{ + Method: "GET", + Path: "/api/v2/devices/" + deviceId, + ExpectedStatus: []int{http.StatusOK}, + RespEncoding: httpclient.EncodingJSON, + RespValue: &device, + } + + _, err = c.Request(&request) + + return +} + +func (c *KoofrClient) DevicesUpdate(deviceId string, deviceUpdate DeviceUpdate) (err error) { + request := httpclient.RequestData{ + Method: "PUT", + Path: "/api/v2/devices/" + deviceId, + ExpectedStatus: []int{http.StatusNoContent}, + ReqEncoding: httpclient.EncodingJSON, + ReqValue: deviceUpdate, + RespConsume: true, + } + + _, err = c.Request(&request) + + return +} + +func (c *KoofrClient) DevicesDelete(deviceId string) (err error) { + request := httpclient.RequestData{ + Method: "DELETE", + Path: "/api/v2/devices/" + deviceId, + ExpectedStatus: []int{http.StatusNoContent}, + RespConsume: true, + } + + _, err = c.Request(&request) + + return +} diff --git a/vendor/github.com/koofr/go-koofrclient/client_files.go b/vendor/github.com/koofr/go-koofrclient/client_files.go new file mode 100644 index 000000000..2e73fef74 --- /dev/null +++ b/vendor/github.com/koofr/go-koofrclient/client_files.go @@ -0,0 +1,294 @@ +package koofrclient + +import ( + "fmt" + "io" + "net/http" + "net/url" + "path" + + "github.com/koofr/go-httpclient" +) + +var ErrCannotOverwrite = fmt.Errorf("Can not overwrite (filter constraint fails)") +var ErrCannotRemove = fmt.Errorf("Can not remove (filter constraint fails)") + +func (c *KoofrClient) FilesInfo(mountId string, path string) (info FileInfo, err error) { + params := url.Values{} + params.Set("path", path) + + request := httpclient.RequestData{ + Method: "GET", + Path: "/api/v2/mounts/" + mountId + "/files/info", + Params: params, + ExpectedStatus: []int{http.StatusOK}, + RespEncoding: httpclient.EncodingJSON, + RespValue: &info, + } + + _, err = c.Request(&request) + + return +} + +func (c *KoofrClient) FilesList(mountId string, basePath string) (files []FileInfo, err error) { + f := &struct { + Files *[]FileInfo + }{&files} + + params := url.Values{} + params.Set("path", basePath) + + request := httpclient.RequestData{ + Method: "GET", + Path: "/api/v2/mounts/" + mountId + "/files/list", + Params: params, + ExpectedStatus: []int{http.StatusOK}, + RespEncoding: httpclient.EncodingJSON, + RespValue: &f, + } + + _, err = c.Request(&request) + + if err != nil { + return + } + + for i := range files { + files[i].Path = path.Join(basePath, files[i].Name) + } + + return +} + +func (c *KoofrClient) FilesTree(mountId string, path string) (tree FileTree, err error) { + params := url.Values{} + params.Set("path", path) + + request := httpclient.RequestData{ + Method: "GET", + Path: "/api/v2/mounts/" + mountId + "/files/tree", + Params: params, + ExpectedStatus: []int{http.StatusOK}, + RespEncoding: httpclient.EncodingJSON, + RespValue: &tree, + } + + _, err = c.Request(&request) + + return +} + +func (c *KoofrClient) FilesDelete(mountId string, path string) (err error) { + return c.filesDelete(mountId, path, nil) +} + +func (c *KoofrClient) FilesDeleteIf(mountId string, path string, deleteFilter *DeleteFilter) (err error) { + return c.filesDelete(mountId, path, deleteFilter) +} + +func (c *KoofrClient) filesDelete(mountId string, path string, deleteFilter *DeleteFilter) (err error) { + params := url.Values{} + params.Set("path", path) + + if deleteFilter != nil { + if deleteFilter.Size != nil { + params.Set("removeIfSize", fmt.Sprintf("%d", *deleteFilter.Size)) + } + if deleteFilter.Modified != nil { + params.Set("removeIfModified", fmt.Sprintf("%d", *deleteFilter.Modified)) + } + if deleteFilter.Hash != nil { + params.Set("removeIfHash", fmt.Sprintf("%s", *deleteFilter.Hash)) + } + if deleteFilter.IfEmpty { + params.Set("removeIfEmpty", "") + } + } + + request := httpclient.RequestData{ + Method: "DELETE", + Path: "/api/v2/mounts/" + mountId + "/files/remove", + Params: params, + ExpectedStatus: []int{http.StatusOK}, + RespConsume: true, + } + + _, err = c.Request(&request) + + if err != nil { + switch err := err.(type) { + case httpclient.InvalidStatusError: + if err.Got == http.StatusConflict { + return ErrCannotRemove + } + default: + return err + } + + } + + return +} + +func (c *KoofrClient) FilesNewFolder(mountId string, path string, name string) (err error) { + reqData := FolderCreate{name} + + params := url.Values{} + params.Set("path", path) + + request := httpclient.RequestData{ + Method: "POST", + Path: "/api/v2/mounts/" + mountId + "/files/folder", + Params: params, + ExpectedStatus: []int{http.StatusOK, http.StatusCreated}, + ReqEncoding: httpclient.EncodingJSON, + ReqValue: reqData, + RespConsume: true, + } + + _, err = c.Request(&request) + + return +} + +func (c *KoofrClient) FilesCopy(mountId string, path string, toMountId string, toPath string) (err error) { + reqData := FileCopy{toMountId, toPath} + + params := url.Values{} + params.Set("path", path) + + request := httpclient.RequestData{ + Method: "PUT", + Path: "/api/v2/mounts/" + mountId + "/files/copy", + Params: params, + ExpectedStatus: []int{http.StatusOK}, + ReqEncoding: httpclient.EncodingJSON, + ReqValue: reqData, + RespConsume: true, + } + + _, err = c.Request(&request) + + return +} + +func (c *KoofrClient) FilesMove(mountId string, path string, toMountId string, toPath string) (err error) { + reqData := FileMove{toMountId, toPath} + + params := url.Values{} + params.Set("path", path) + + request := httpclient.RequestData{ + Method: "PUT", + Path: "/api/v2/mounts/" + mountId + "/files/move", + Params: params, + ExpectedStatus: []int{http.StatusOK}, + ReqEncoding: httpclient.EncodingJSON, + ReqValue: reqData, + RespConsume: true, + } + + _, err = c.Request(&request) + + return +} + +func (c *KoofrClient) FilesGetRange(mountId string, path string, span *FileSpan) (reader io.ReadCloser, err error) { + params := url.Values{} + params.Set("path", path) + + request := httpclient.RequestData{ + Method: "GET", + Path: "/content/api/v2/mounts/" + mountId + "/files/get", + Params: params, + Headers: make(http.Header), + ExpectedStatus: []int{http.StatusOK, http.StatusPartialContent}, + } + + if span != nil { + if span.End == -1 { + request.Headers.Set("Range", fmt.Sprintf("bytes=%d-", span.Start)) + } else { + request.Headers.Set("Range", fmt.Sprintf("bytes=%d-%d", span.Start, span.End)) + } + } + + res, err := c.Request(&request) + + if err != nil { + return + } + + reader = res.Body + + return +} + +func (c *KoofrClient) FilesGet(mountId string, path string) (reader io.ReadCloser, err error) { + return c.FilesGetRange(mountId, path, nil) +} + +func (c *KoofrClient) FilesPut(mountId string, path string, name string, reader io.Reader) (newName string, err error) { + info, err := c.FilesPutOptions(mountId, path, name, reader, nil) + return info.Name, err +} + +func (c *KoofrClient) FilesPutOptions(mountId string, path string, name string, reader io.Reader, putFilter *PutFilter) (fileInfo *FileInfo, err error) { + params := url.Values{} + params.Set("path", path) + params.Set("filename", name) + params.Set("info", "true") + + if putFilter != nil { + if putFilter.Size != nil { + params.Set("overwriteIfSize", fmt.Sprintf("%d", *putFilter.Size)) + } + if putFilter.Modified != nil { + params.Set("overwriteIfModified", fmt.Sprintf("%d", *putFilter.Modified)) + } + if putFilter.Hash != nil { + params.Set("overwriteIfHash", fmt.Sprintf("%s", *putFilter.Hash)) + } + if putFilter.IgnoreNonExisting { + params.Set("overwriteIgnoreNonexisting", "") + } + if putFilter.NoRename { + params.Set("autorename", "false") + } + if putFilter.ForceOverwrite { + params.Set("overwrite", "true") + } + } + + request := httpclient.RequestData{ + Method: "POST", + Path: "/content/api/v2/mounts/" + mountId + "/files/put", + Params: params, + ExpectedStatus: []int{http.StatusOK}, + RespEncoding: httpclient.EncodingJSON, + RespValue: &fileInfo, + } + + err = request.UploadFile("file", "dummy", reader) + + if err != nil { + return + } + + _, err = c.Request(&request) + + if err != nil { + + switch err := err.(type) { + case httpclient.InvalidStatusError: + if err.Got == http.StatusConflict { + return nil, ErrCannotOverwrite + } + default: + return nil, err + } + } + + return +} diff --git a/vendor/github.com/koofr/go-koofrclient/client_mount.go b/vendor/github.com/koofr/go-koofrclient/client_mount.go new file mode 100644 index 000000000..f5ea21ca0 --- /dev/null +++ b/vendor/github.com/koofr/go-koofrclient/client_mount.go @@ -0,0 +1,38 @@ +package koofrclient + +import ( + "github.com/koofr/go-httpclient" + "net/http" +) + +func (c *KoofrClient) Mounts() (mounts []Mount, err error) { + d := &struct { + Mounts *[]Mount + }{&mounts} + + request := httpclient.RequestData{ + Method: "GET", + Path: "/api/v2/mounts", + ExpectedStatus: []int{http.StatusOK}, + RespEncoding: httpclient.EncodingJSON, + RespValue: &d, + } + + _, err = c.Request(&request) + + return +} + +func (c *KoofrClient) MountsDetails(mountId string) (mount Mount, err error) { + request := httpclient.RequestData{ + Method: "GET", + Path: "/api/v2/mounts/" + mountId, + ExpectedStatus: []int{http.StatusOK}, + RespEncoding: httpclient.EncodingJSON, + RespValue: &mount, + } + + _, err = c.Request(&request) + + return +} diff --git a/vendor/github.com/koofr/go-koofrclient/client_shared.go b/vendor/github.com/koofr/go-koofrclient/client_shared.go new file mode 100644 index 000000000..414a215e0 --- /dev/null +++ b/vendor/github.com/koofr/go-koofrclient/client_shared.go @@ -0,0 +1,25 @@ +package koofrclient + +import ( + "net/http" + + "github.com/koofr/go-httpclient" +) + +func (c *KoofrClient) Shared() (shared []Shared, err error) { + d := &struct { + Files *[]Shared + }{&shared} + + request := httpclient.RequestData{ + Method: "GET", + Path: "/api/v2/shared", + ExpectedStatus: []int{http.StatusOK}, + RespEncoding: httpclient.EncodingJSON, + RespValue: &d, + } + + _, err = c.Request(&request) + + return +} diff --git a/vendor/github.com/koofr/go-koofrclient/client_user.go b/vendor/github.com/koofr/go-koofrclient/client_user.go new file mode 100644 index 000000000..93cde5f8f --- /dev/null +++ b/vendor/github.com/koofr/go-koofrclient/client_user.go @@ -0,0 +1,20 @@ +package koofrclient + +import ( + "github.com/koofr/go-httpclient" + "net/http" +) + +func (c *KoofrClient) UserInfo() (user User, err error) { + request := httpclient.RequestData{ + Method: "GET", + Path: "/api/v2/user", + ExpectedStatus: []int{http.StatusOK}, + RespEncoding: httpclient.EncodingJSON, + RespValue: &user, + } + + _, err = c.Request(&request) + + return +} diff --git a/vendor/modules.txt b/vendor/modules.txt index af2883434..5fa5a732c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -98,6 +98,10 @@ github.com/jlaffaye/ftp github.com/jmespath/go-jmespath # github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 github.com/kardianos/osext +# github.com/koofr/go-httpclient v0.0.0-20180104120329-03786175608a +github.com/koofr/go-httpclient +# github.com/koofr/go-koofrclient v0.0.0-20190131164641-7f327592caff +github.com/koofr/go-koofrclient # github.com/kr/fs v0.1.0 github.com/kr/fs # github.com/mattn/go-runewidth v0.0.4