github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/util/user/user.go (about) 1 package user 2 3 import ( 4 "os/user" 5 "path/filepath" 6 7 "crypto/rand" 8 "crypto/rsa" 9 "crypto/x509" 10 "encoding/base64" 11 "encoding/pem" 12 "io/ioutil" 13 "os" 14 15 "github.com/tickoalcantara12/micro/v3/service/logger" 16 ) 17 18 var ( 19 Dir = "" 20 path = ".micro" 21 ) 22 23 func init() { 24 user, err := user.Current() 25 if err != nil { 26 logger.Fatalf(err.Error()) 27 } 28 Dir = filepath.Join(user.HomeDir, path) 29 err = os.MkdirAll(Dir, 0700) 30 if err != nil { 31 logger.Fatalf(err.Error()) 32 } 33 } 34 35 // GetConfigSecretKey returns local keys or generates and returns them for 36 // config secret encoding/decoding. 37 func GetConfigSecretKey() (string, error) { 38 key := filepath.Join(Dir, "config_secret_key") 39 if !fileExists(key) { 40 err := setupConfigSecretKey(key) 41 if err != nil { 42 return "", err 43 } 44 } 45 logger.Debugf("Loading config key from %v", key) 46 dat, err := ioutil.ReadFile(key) 47 if err != nil { 48 return "", err 49 } 50 return string(dat), nil 51 } 52 53 func setupConfigSecretKey(path string) error { 54 logger.Debugf("Setting up config key to %v", path) 55 bytes := make([]byte, 32) //generate a random 32 byte key for AES-256 56 if _, err := rand.Read(bytes); err != nil { 57 return err 58 } 59 file, err := os.OpenFile(path, os.O_RDONLY|os.O_CREATE, 0644) 60 if err != nil { 61 return err 62 } 63 file.Close() 64 65 err = ioutil.WriteFile(path, []byte(base64.StdEncoding.EncodeToString(bytes)), 0600) 66 if err != nil { 67 return err 68 } 69 70 return nil 71 } 72 73 // GetJWTCerts returns local keys or generates and returns them for JWT auth.GetJWTCerts 74 // This is only here for "0 dep", so people don't have to create and load the certs themselves, 75 // not really intended for serious production use. 76 func GetJWTCerts() ([]byte, []byte, error) { 77 privKey := filepath.Join(Dir, "id_rsa") 78 pubKey := filepath.Join(Dir, "id_rsa.pub") 79 80 logger.Debugf("Loading keys %v and %v", privKey, pubKey) 81 if !fileExists(privKey) || !fileExists(pubKey) { 82 err := setupKeys(privKey, pubKey) 83 if err != nil { 84 return nil, nil, err 85 } 86 } 87 privDat, err := ioutil.ReadFile(privKey) 88 if err != nil { 89 return nil, nil, err 90 } 91 pubDat, err := ioutil.ReadFile(pubKey) 92 if err != nil { 93 return nil, nil, err 94 } 95 return privDat, pubDat, nil 96 } 97 98 func setupKeys(privKey, pubKey string) error { 99 logger.Infof("Setting up keys for JWT at %v and %v", privKey, pubKey) 100 bitSize := 4096 101 privateKey, err := generatePrivateKey(bitSize) 102 if err != nil { 103 return err 104 } 105 106 publicKeyBytes, err := generatePublicKey(&privateKey.PublicKey) 107 if err != nil { 108 return err 109 } 110 111 privateKeyBytes, err := encodePrivateKeyToPEM(privateKey) 112 if err != nil { 113 return err 114 } 115 116 err = writeKeyToFile(privateKeyBytes, privKey) 117 if err != nil { 118 return err 119 } 120 121 err = writeKeyToFile([]byte(publicKeyBytes), pubKey) 122 if err != nil { 123 return err 124 } 125 return nil 126 } 127 128 func fileExists(filename string) bool { 129 info, err := os.Stat(filename) 130 if os.IsNotExist(err) { 131 return false 132 } 133 return !info.IsDir() 134 } 135 136 // taken from https://gist.github.com/devinodaniel/8f9b8a4f31573f428f29ec0e884e6673 137 138 // generatePrivateKey creates a RSA Private Key of specified byte size 139 func generatePrivateKey(bitSize int) (*rsa.PrivateKey, error) { 140 // Private Key generation 141 privateKey, err := rsa.GenerateKey(rand.Reader, bitSize) 142 if err != nil { 143 return nil, err 144 } 145 146 // Validate Private Key 147 err = privateKey.Validate() 148 if err != nil { 149 return nil, err 150 } 151 152 return privateKey, nil 153 } 154 155 // encodePrivateKeyToPEM encodes Private Key from RSA to PEM format 156 func encodePrivateKeyToPEM(privateKey *rsa.PrivateKey) ([]byte, error) { 157 // Get ASN.1 DER format 158 privDER := x509.MarshalPKCS1PrivateKey(privateKey) 159 160 // pem.Block 161 privBlock := pem.Block{ 162 Type: "RSA PRIVATE KEY", 163 Headers: nil, 164 Bytes: privDER, 165 } 166 167 // Private key in PEM format 168 privatePEM := pem.EncodeToMemory(&privBlock) 169 170 return privatePEM, nil 171 } 172 173 func generatePublicKey(publickey *rsa.PublicKey) ([]byte, error) { 174 pubDER, err := x509.MarshalPKIXPublicKey(publickey) 175 if err != nil { 176 return nil, err 177 } 178 pubBlock := pem.Block{ 179 Type: "PUBLIC KEY", 180 Headers: nil, 181 Bytes: pubDER, 182 } 183 pubPEM := pem.EncodeToMemory(&pubBlock) 184 185 return pubPEM, nil 186 } 187 188 // writePemToFile writes keys to a file 189 func writeKeyToFile(keyBytes []byte, saveFileTo string) error { 190 file, err := os.OpenFile(saveFileTo, os.O_RDONLY|os.O_CREATE, 0644) 191 if err != nil { 192 return err 193 } 194 file.Close() 195 196 err = ioutil.WriteFile(saveFileTo, []byte(base64.StdEncoding.EncodeToString(keyBytes)), 0600) 197 if err != nil { 198 return err 199 } 200 201 return nil 202 }