package identity import ( "crypto/rand" "encoding/base64" "errors" "fmt" "somehole.com/common/security/signature" ) const ( RetryCreateId = 3 ) type identity interface { GetId() []byte GetPublicKey() []byte GetPublicKeySignature() []byte } type Id [8]byte func (i Id) String() (out string) { out = base64.StdEncoding.EncodeToString(i[:]) return } type Identity struct { Id Id PublicKey signature.PublicKey PublicKeySignature signature.Signature } func NewIdentity(ident identity) (i Identity, err error) { id := ident.GetId() if len(id) != 8 { err = errors.New("wrong size id") return } pubKey := ident.GetPublicKey() if len(pubKey) != 96 { err = errors.New("wrong size public key") return } pubKeySig := ident.GetPublicKeySignature() if len(pubKeySig) != 48 { err = errors.New("wrong size public key signature") return } i = Identity{ Id: Id(id), PublicKey: signature.PublicKey(pubKey), PublicKeySignature: signature.Signature(pubKeySig), } return } func (i Identity) String() (out string) { b := make([]byte, 0) b = append(b, i.Id[:]...) b = append(b, i.PublicKey[:]...) b = append(b, i.PublicKeySignature[:]...) out = base64.StdEncoding.EncodeToString(b) return } func ParseIdentityString(in string) (i Identity, err error) { var b []byte b, err = base64.StdEncoding.DecodeString(in) if err != nil { return } if len(b) != 8+96+48 { err = errors.New("wrong for size identity data in string") return } i = Identity{ Id: Id(b[0:8]), PublicKey: signature.PublicKey(b[8:104]), PublicKeySignature: signature.Signature(b[104:152]), } return } type IdentityService struct { identities map[Id]Identity } func NewIdentityService() (srv *IdentityService) { srv = &IdentityService{ identities: make(map[Id]Identity), } return } func (srv *IdentityService) NewId() (id Id, err error) { var idBytes = make([]byte, 8) for i := 0; i < RetryCreateId; i++ { rand.Read(idBytes) if _, exists := srv.identities[id]; exists { err = fmt.Errorf("could only creat colliding ids in %d tries", RetryCreateId) continue } id = Id(idBytes) err = nil break } return } func (srv *IdentityService) AddIdentity(id Id, identity Identity) (err error) { _, exists := srv.identities[id] if exists { err = fmt.Errorf("failed to add identity") return } srv.identities[id] = identity return }