package saltyim import ( "crypto/sha256" "encoding/json" "fmt" "io/ioutil" "net/http" "strings" ) // Addr represents a Salty IM User's Address type Addr struct { User string Domain string } // IsZero returns true if the address is empty func (a Addr) IsZero() bool { return a.User == "" && a.Domain == "" } func (a Addr) String() string { return fmt.Sprintf("%s@%s", a.User, a.Domain) } // Hash returns the Hex(SHA256Sum()) of the Address func (a Addr) Hash() string { return fmt.Sprintf("%x", sha256.Sum256([]byte(a.String()))) } // Formatted returns a formatted user used in the Salty Message Format // ) \n func (a Addr) Formatted() string { return fmt.Sprintf("(%s)", a) } // URI returns the Well-Known URI for this Addr func (a Addr) URI() string { return fmt.Sprintf("https://%s/.well-known/salty/%s.json", a.Domain, a.User) } // HashURI returns the Well-Known HashURI for this Addr func (a Addr) HashURI() string { return fmt.Sprintf("https://%s/.well-known/salty/%s.json", a.Domain, a.Hash()) } // ParseAddr parsers a Salty Address for a user into it's user and domain // parts and returns an Addr object with the User and Domain and a method // for returning the expected User's Well-Known URI func ParseAddr(addr string) (Addr, error) { parts := strings.Split(addr, "@") if len(parts) != 2 { return Addr{}, fmt.Errorf("expected nick@domain found %q", addr) } return Addr{parts[0], parts[1]}, nil } // Lookup looks up a Salty Address for a User by parsing the user's domain and // making a request to the user's Well-Known URI expected to be located at // https://domain/.well-known/salty/.json func Lookup(addr string) (Config, error) { a, err := ParseAddr(addr) if err != nil { return Config{}, err } config, err := fetchConfig(a.HashURI()) if err != nil { // Fallback to plain user nick config, err = fetchConfig(a.URI()) } return config, err } func fetchConfig(addr string) (Config, error) { // Attempt using hash res, err := Request(http.MethodGet, addr, nil, nil) if err != nil { return Config{}, err } data, err := ioutil.ReadAll(res.Body) if err != nil { return Config{}, err } var config Config if err := json.Unmarshal(data, &config); err != nil { return Config{}, err } return config, err }