I am having some trouble with the UnmarshalJSON
and MarshalJSON
i am not sure i understand them correctly or atleast i have an error that i have not been able to spot and in my 3 hours of googling i haven't been able find, so here goes.
I have the following User struct
type User struct {
ID uuid.UUID `gorm:"primaryKey,type:string,size:36,<-:create" json:"id"`
Username string `gorm:"unique" json:"username"`
Password PasswordHash `gorm:"type:string" json:"password"`
CreatedAt time.Time `gorm:"autoCreateTime:milli" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime:milli" json:"updated_at,omitempty"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at,omitempty"`
}
which when i try to convert into JSON, with the json.Marshal
function from the build in encoding/json
library, i get the following:
{"id":"3843298e-74d4-4dd7-8eff-007ab34a4c19","username":"root","password":{},"created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","deleted_at":null}
I expected some thing like:
{"id":"3843298e-74d4-4dd7-8eff-007ab34a4c19","username":"root","password":"$argon2id$v=19$m=4194304,t=1,p=64$Z9EFSTk26TQxx Qv9g58gQ$4At0rvvv9trRcFZmSMXY0nISBuEt 1X8mCRAYbyXqSs","created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","deleted_at":null}
i can't seem to get the password
field to be a string of the hashed password.
even when i have the following methods on the PasswordHash
struct
type Params struct {
memory uint32
iterations uint32
parallelism uint8
saltLength uint32
keyLength uint32
}
type PasswordHash struct {
hash []byte
salt []byte
params Params
}
func (h *PasswordHash) String() string {
b64Salt := base64.RawStdEncoding.EncodeToString(h.salt)
b64Hash := base64.RawStdEncoding.EncodeToString(h.hash)
return fmt.Sprintf(
"$%s$v=%d$m=%d,t=%d,p=%d$%s$%s",
algoName,
argon2.Version,
h.params.memory,
h.params.iterations,
h.params.parallelism,
b64Salt,
b64Hash,
)
}
func (h *PasswordHash) UnmarshalJSON(data []byte) error {
var v string
if err := json.Unmarshal(data, &v); err != nil {
return err
}
params, salt, hash, err := decodeHash(v)
if err != nil {
return err
}
h.params = params
h.salt = salt
h.hash = hash
return nil
}
func (h *PasswordHash) MarshalJSON() ([]byte, error) {
//return []byte(h.String()), nil
return json.Marshal(h.String())
}
So i guess my question is, shouldn't the MarshalJSON
be called on the PasswordHash struct when trying to convert the user to JSON? and if so how come i can't seem to get it to be a string value?
CodePudding user response:
You have MarshalJSON
defined with a receiver of *PasswordHash
, but your value is type PasswordHash
. Change the receiver to PasswordHash
and it works as expected: https://go.dev/play/p/WukE_5JBEPL