duanbo6482
2015-06-18 15:19 阅读 64
已采纳

在golang结构中转换字符串

I've got a json file of AES encrypted secrets. The structure is:

{
    "username": "asdf123ASLdf3",
    "password": "elisjdvo4etQW"
}

And a struct to hold these values

type Secrets struct {
    Username string `json:"username"`
    Password string `json:"password"`
}

It's easy to load the encrypted json values into the struct, but what I really want is a struct with the unencrypted values.

So, for each value, I'd like to run it though a function:

aesDecrypt(key string, value string) string

I'm happy to have this done on the first load, or to move everything over into a new struct.

I would like to avoid repeating the json keys or the field names.

What's the best way to do this?

(Also open to other ways to manage encrypted secrets in Go)

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

1条回答 默认 最新

  • 已采纳
    dpvomqeu396484 dpvomqeu396484 2015-06-18 15:59

    One option is to define a custom JSON Unmarshaler. Another is, as you mention, copy it to another struct.

    1. Implementing the Unmarshaler interface

      The key insight is knowing that you can override json.Unmarshal's behaviour by implementing the Unmarshaler interface. In our case, that means defining a function func (ss *Secrets) UnmarshalJSON(bb []byte) error that will do the AES Decryption when you try to unmarshal any JSON to a Secrets.

      package main
      
      import "fmt"
      import "encoding/json"
      
      type Secrets struct {
          Username string `json:"username"`
          Password string `json:"password"`
      }
      
      func main() {
          jj := []byte(`{
              "username": "asdf123ASLdf3",
              "password": "elisjdvo4etQW"
          }`)
          var ss Secrets
          json.Unmarshal(jj, &ss)
          fmt.Println(ss)
      }
      
      func aesDecrypt(key, value string) string {
          return fmt.Sprintf("'%s' decrypted with key '%s'", value, key)
      }
      
      func (ss *Secrets) UnmarshalJSON(bb []byte) error {
          var objmap map[string]*string
          err := json.Unmarshal(bb, &objmap)
          ss.Username = aesDecrypt("my key", *objmap["password"])
          ss.Password = aesDecrypt("my key", *objmap["username"])
          return err
      }
      

      This outputs a Secrets struct:

      {'elisjdvo4etQW' decrypted with key 'my key'
       'asdf123ASLdf3' decrypted with key 'my key'}
      

      See it in action at the Go Playground.

    2. Copying to another struct

      You could simply make a new Secrets struct every time you need to decrypt the JSON. This could be tedious if you do it alot, or if you have no need for the intermediate state.

      package main
      
      import "fmt"
      import "encoding/json"
      
      type Secrets struct {
          Username string `json:"username"`
          Password string `json:"password"`
      }
      
      func main() {
          jj := []byte(`{
              "username": "asdf123ASLdf3",
              "password": "elisjdvo4etQW"
          }`)
          var ss Secrets
          json.Unmarshal(jj, &ss)
          decoded := Secrets{
              aesDecrypt(ss.Username, "my key"),
              aesDecrypt(ss.Password, "my key")}
          fmt.Println(decoded)
      }
      
      func aesDecrypt(key, value string) string {
          return fmt.Sprintf("'%s' decrypted with key '%s'", value, key)
      }
      

      Check it out at Go Playground.

      This has the same output as above:

      {'elisjdvo4etQW' decrypted with key 'my key'
       'asdf123ASLdf3' decrypted with key 'my key'}
      

    Obviously, you would use a different version of aesDecrypt, mine's just a dummy. And, as always, you should actually be checking the returned errors in your own code.

    点赞 评论 复制链接分享

相关推荐