security/identity/identity.go
2024-09-30 19:02:10 -04:00

121 lines
2.4 KiB
Go

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
}