Add LookupID/LookupAll client functions
This commit is contained in:
parent
249b99f46f
commit
2c3e0b3df6
90
client.go
90
client.go
@ -62,21 +62,45 @@ type Client struct {
|
|||||||
GetPubkey func(serverName string) (ed25519.PublicKey, error)
|
GetPubkey func(serverName string) (ed25519.PublicKey, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup looks up the profile descriptor for the given ID.
|
// Lookup looks up the profile descriptor for the given resource.
|
||||||
func (c Client) Lookup(id string) (*Descriptor, error) {
|
func (c Client) Lookup(resource string) (*Descriptor, error) {
|
||||||
wfdesc, err := webfinger.LookupAcct(id)
|
out := &Descriptor{}
|
||||||
|
return out, c.lookup(resource, "", out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupID looks up the profile descriptor that matches the given ID
|
||||||
|
// for the given resource.
|
||||||
|
func (c Client) LookupID(resource, id string) (*Descriptor, error) {
|
||||||
|
out := &Descriptor{}
|
||||||
|
return out, c.lookup(resource, id, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup looks up all the available profile descriptors for the given resource.
|
||||||
|
func (c Client) LookupAll(resource string) (map[string]*Descriptor, error) {
|
||||||
|
out := map[string]*Descriptor{}
|
||||||
|
return out, c.lookup(resource, "", &out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Client) lookup(resource, id string, dest any) error {
|
||||||
|
wfdesc, err := webfinger.LookupAcct(resource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
pfdLink, ok := wfdesc.LinkByType("application/x-pfd+json")
|
pfdLink, ok := wfdesc.LinkByType("application/x-pfd+json")
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("server does not support the profilefed protocol")
|
return errors.New("server does not support the profilefed protocol")
|
||||||
}
|
}
|
||||||
|
|
||||||
pfdURL, err := url.Parse(pfdLink.Href)
|
pfdURL, err := url.Parse(pfdLink.Href)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if id != "" {
|
||||||
|
q := pfdURL.Query()
|
||||||
|
q.Set("id", id)
|
||||||
|
pfdURL.RawQuery = q.Encode()
|
||||||
}
|
}
|
||||||
|
|
||||||
pubkeySaved := false
|
pubkeySaved := false
|
||||||
@ -84,77 +108,77 @@ func (c Client) Lookup(id string) (*Descriptor, error) {
|
|||||||
if errors.Is(err, ErrPubkeyNotFound) {
|
if errors.Is(err, ErrPubkeyNotFound) {
|
||||||
info, _, err := getServerInfo(pfdURL.Scheme, pfdURL.Host)
|
info, _, err := getServerInfo(pfdURL.Scheme, pfdURL.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
pubkey, err = base64.StdEncoding.DecodeString(info.PublicKey)
|
pubkey, err = base64.StdEncoding.DecodeString(info.PublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.SavePubkey(pfdURL.Host, info.PreviousNames, pubkey)
|
err = c.SavePubkey(pfdURL.Host, info.PreviousNames, pubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
pubkeySaved = true
|
pubkeySaved = true
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := http.Get(pfdLink.Href)
|
res, err := http.Get(pfdURL.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
|
|
||||||
if err := checkResp(res, "getProfileDescriptor"); err != nil {
|
if err := checkResp(res, "getProfileDescriptor"); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := io.ReadAll(io.LimitReader(res.Body, responseSizeLimit))
|
data, err := io.ReadAll(io.LimitReader(res.Body, responseSizeLimit))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := res.Body.Close(); err != nil {
|
if err := res.Body.Close(); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sig, err := getSignature(res)
|
sig, err := getSignature(res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ed25519.Verify(pubkey, data, sig) {
|
if !ed25519.Verify(pubkey, data, sig) {
|
||||||
// If the pubkey was just saved in the current request, we probably
|
// If the pubkey was just saved in the current request, we probably
|
||||||
// already have the newest one, so just return a mismatch error.
|
// already have the newest one, so just return a mismatch error.
|
||||||
if pubkeySaved {
|
if pubkeySaved {
|
||||||
return nil, ErrSignatureMismatch
|
return ErrSignatureMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := serverInfoReq(pfdURL.Scheme, pfdURL.Host)
|
res, err := serverInfoReq(pfdURL.Scheme, pfdURL.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
serverData, err := io.ReadAll(io.LimitReader(res.Body, responseSizeLimit))
|
serverData, err := io.ReadAll(io.LimitReader(res.Body, responseSizeLimit))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var info serverInfoData
|
var info serverInfoData
|
||||||
err = json.Unmarshal(serverData, &info)
|
err = json.Unmarshal(serverData, &info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
newPubkey, err := base64.StdEncoding.DecodeString(info.PublicKey)
|
newPubkey, err := base64.StdEncoding.DecodeString(info.PublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if bytes.Equal(pubkey, newPubkey) {
|
if bytes.Equal(pubkey, newPubkey) {
|
||||||
return nil, ErrSignatureMismatch
|
return ErrSignatureMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
verified := false
|
verified := false
|
||||||
@ -167,39 +191,29 @@ func (c Client) Lookup(id string) (*Descriptor, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !verified {
|
if !verified {
|
||||||
return nil, ErrSignatureMismatch
|
return ErrSignatureMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
infoSig, err := getSignature(res)
|
infoSig, err := getSignature(res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ed25519.Verify(newPubkey, infoSig, serverData) {
|
if !ed25519.Verify(newPubkey, infoSig, serverData) {
|
||||||
return nil, ErrSignatureMismatch
|
return ErrSignatureMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.SavePubkey(pfdURL.Host, info.PreviousNames, newPubkey)
|
err = c.SavePubkey(pfdURL.Host, info.PreviousNames, newPubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ed25519.Verify(newPubkey, data, sig) {
|
if !ed25519.Verify(newPubkey, data, sig) {
|
||||||
return nil, ErrSignatureMismatch
|
return ErrSignatureMismatch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
desc := &Descriptor{}
|
return json.Unmarshal(data, dest)
|
||||||
err = json.Unmarshal(data, desc)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if desc.Role == "" {
|
|
||||||
desc.Role = RoleUser
|
|
||||||
}
|
|
||||||
|
|
||||||
return desc, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// serverInfoReq performs an HTTP request to retrieve server information.
|
// serverInfoReq performs an HTTP request to retrieve server information.
|
||||||
|
Loading…
Reference in New Issue
Block a user