code.vegaprotocol.io/vega@v0.79.0/paths/file.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package paths 17 18 import ( 19 "bytes" 20 "encoding/json" 21 "errors" 22 "fmt" 23 "io" 24 "net/http" 25 26 vgcrypto "code.vegaprotocol.io/vega/libs/crypto" 27 vgfs "code.vegaprotocol.io/vega/libs/fs" 28 29 "github.com/BurntSushi/toml" 30 ) 31 32 var ( 33 ErrEmptyResponse = errors.New("empty response") 34 ErrEmptyFile = errors.New("empty file") 35 ErrContentLooksLikeHTML = errors.New("the content looks like it contains HTML, be sure your file has TOML formatting") 36 ErrContentLooksLikeJSON = errors.New("the content looks like it contains JSON, be sure your file has TOML formatting") 37 ) 38 39 func FetchStructuredFile(url string, v interface{}) error { 40 resp, err := http.Get(url) //nolint:noctx 41 if err != nil { 42 return fmt.Errorf("couldn't load file: %w", err) 43 } 44 defer resp.Body.Close() 45 46 if resp.StatusCode != http.StatusOK { 47 return errors.New(http.StatusText(resp.StatusCode)) 48 } 49 50 body, err := io.ReadAll(resp.Body) 51 if err != nil { 52 return fmt.Errorf("couldn't read HTTP response body: %w", err) 53 } 54 55 if len(body) == 0 { 56 return ErrEmptyResponse 57 } 58 59 if err := decodeTOMLFile(body, v); err != nil { 60 return err 61 } 62 63 return nil 64 } 65 66 func decodeTOMLFile(content []byte, v interface{}) error { 67 if content[0] == '<' { 68 return ErrContentLooksLikeHTML 69 } 70 71 if content[0] == '{' { 72 return ErrContentLooksLikeJSON 73 } 74 75 if _, err := toml.Decode(string(content), v); err != nil { 76 return fmt.Errorf("invalid TOML document: %w", err) 77 } 78 79 return nil 80 } 81 82 func ReadStructuredFile(path string, v interface{}) error { 83 buf, err := vgfs.ReadFile(path) 84 if err != nil { 85 return fmt.Errorf("couldn't read file: %w", err) 86 } 87 88 if len(buf) == 0 { 89 return ErrEmptyFile 90 } 91 92 if err := decodeTOMLFile(buf, v); err != nil { 93 return err 94 } 95 96 return nil 97 } 98 99 func WriteStructuredFile(path string, v interface{}) error { 100 buf := new(bytes.Buffer) 101 if err := toml.NewEncoder(buf).Encode(v); err != nil { 102 return fmt.Errorf("couldn't encode to TOML: %w", err) 103 } 104 105 if err := vgfs.WriteFile(path, buf.Bytes()); err != nil { 106 return fmt.Errorf("couldn't write file: %w", err) 107 } 108 109 return nil 110 } 111 112 func ReadEncryptedFile(path string, passphrase string, v interface{}) error { 113 encryptedBuf, err := vgfs.ReadFile(path) 114 if err != nil { 115 return fmt.Errorf("couldn't read secure file: %w", err) 116 } 117 118 if len(encryptedBuf) == 0 { 119 return ErrEmptyFile 120 } 121 122 buf, err := vgcrypto.Decrypt(encryptedBuf, passphrase) 123 if err != nil { 124 return fmt.Errorf("couldn't decrypt content: %w", err) 125 } 126 127 err = json.Unmarshal(buf, v) 128 if err != nil { 129 return fmt.Errorf("couldn't unmarshal content: %w", err) 130 } 131 132 return nil 133 } 134 135 func WriteEncryptedFile(path string, passphrase string, v interface{}) error { 136 buf, err := json.Marshal(v) 137 if err != nil { 138 return fmt.Errorf("couldn't marshal content: %w", err) 139 } 140 141 encryptedBuf, err := vgcrypto.Encrypt(buf, passphrase) 142 if err != nil { 143 return fmt.Errorf("couldn't encrypt content: %w", err) 144 } 145 146 if err := vgfs.WriteFile(path, encryptedBuf); err != nil { 147 return fmt.Errorf("couldn't write secure file: %w", err) 148 } 149 150 return nil 151 }