package sigcred import ( "dehub.dev/src/dehub.git/fs" "dehub.dev/src/dehub.git/typeobj" ) // Signifier describes the methods that all signifiers must implement. type Signifier interface { // Sign returns a credential containing a signature of the given data. // // tree can be used to find the Signifier at a particular snapshot. Sign(fs.FS, []byte) (CredentialUnion, error) // Signed returns true if the Signifier was used to sign the credential. Signed(fs.FS, CredentialUnion) (bool, error) // Verify asserts that the Signifier produced the given credential for the // given data set, or returns an error. // // tree can be used to find the Signifier at a particular snapshot. Verify(fs.FS, []byte, CredentialUnion) error } // SignifierUnion represents a single signifier for an account. Only one field // should be set on each SignifierUnion. type SignifierUnion struct { PGPPublicKey *SignifierPGP `type:"pgp_public_key"` // LegacyPGPPublicKeyFile is deprecated, only PGPPublicKey should be used LegacyPGPPublicKeyFile *SignifierPGPFile `type:"pgp_public_key_file"` } // MarshalYAML implements the yaml.Marshaler interface. func (s SignifierUnion) MarshalYAML() (interface{}, error) { return typeobj.MarshalYAML(s) } // UnmarshalYAML implements the yaml.Unmarshaler interface. func (s *SignifierUnion) UnmarshalYAML(unmarshal func(interface{}) error) error { if err := typeobj.UnmarshalYAML(s, unmarshal); err != nil { return err } // TODO deprecate PGPPublicKeyFile if s.LegacyPGPPublicKeyFile != nil { s.PGPPublicKey = &SignifierPGP{Path: s.LegacyPGPPublicKeyFile.Path} s.LegacyPGPPublicKeyFile = nil } return nil } // Signifier returns the Signifier instance encapsulated by this SignifierUnion. // // This will panic if no Signifier field is populated. // // accountID is given so as to automatically fill the AccountID field of // credentials returned from Sign, since the underlying implementation doesn't // know what account it's signing for. func (s SignifierUnion) Signifier(accountID string) Signifier { el, _, err := typeobj.Element(s) if err != nil { panic(err) } return accountSignifier(accountID, el.(Signifier)) } type signifierMiddleware struct { Signifier signCallback func(*CredentialUnion) } func (sm signifierMiddleware) Sign(fs fs.FS, data []byte) (CredentialUnion, error) { cred, err := sm.Signifier.Sign(fs, data) if err != nil || sm.signCallback == nil { return cred, err } sm.signCallback(&cred) return cred, nil } // accountSignifier wraps a Signifier to always set the accountID field on // credentials it produces via the Sign method. // // TODO accountSignifier shouldn't be necessary, it's very ugly. It indicates // that CredentialUnion probably shouldn't have AccountID on it, which makes // sense. Some refactoring is required here. func accountSignifier(accountID string, sig Signifier) Signifier { return signifierMiddleware{ Signifier: sig, signCallback: func(cred *CredentialUnion) { cred.AccountID = accountID }, } }