diff --git a/api/client.go b/api/client.go index d68601829729a929b917923eeb1dec5841ce293e..2d56806e077de25199ab82fe1fe0b2076c46c628 100644 --- a/api/client.go +++ b/api/client.go @@ -343,7 +343,7 @@ func (c *Client) GetHealth() interfaces.HealthTracker { return c.network.GetHealthTracker() } -// Returns the switchboard for Registration +// Returns the switchboard for Identity func (c *Client) GetSwitchboard() interfaces.Switchboard { jww.INFO.Printf("GetSwitchboard()") return c.switchboard diff --git a/bindings/ud.go b/bindings/ud.go index bae84a46f6b040a7a366cd51396f0c433278da0a..643066a2ad2417ab444698c63b717101454ea53c 100644 --- a/bindings/ud.go +++ b/bindings/ud.go @@ -44,7 +44,7 @@ func NewUserDiscovery(client *Client)(*UserDiscovery, error){ // network signatures are malformed or if the username is taken. Usernames // cannot be changed after registration at this time. Will fail if the user is // already registered. -// Registration does not go over cmix, it occurs over normal communications +// Identity does not go over cmix, it occurs over normal communications func (ud *UserDiscovery)Register(username string)error{ return ud.ud.Register(username) } diff --git a/cmd/root.go b/cmd/root.go index 36539fba6738c70f00b862802d0642ffbf594017..b19081d3ec1a3507f9f0ff816db940a1c1ead0f0 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -565,7 +565,7 @@ func init() { viper.BindPFlag("log", rootCmd.PersistentFlags().Lookup("log")) rootCmd.Flags().StringP("regcode", "", "", - "Registration code (optional)") + "Identity code (optional)") viper.BindPFlag("regcode", rootCmd.Flags().Lookup("regcode")) rootCmd.Flags().StringP("message", "m", "", "Message to send") diff --git a/globals/statusEvents.go b/globals/statusEvents.go index 9695871da46a8252d42bd838996b1bb7a30330c2..fdf8d6ff99f6ac0c5cbc155eebe1a9c645c0ab8f 100644 --- a/globals/statusEvents.go +++ b/globals/statusEvents.go @@ -7,9 +7,9 @@ package globals -//Registration +//Identity const REG_KEYGEN = 1 //Generating Cryptographic Keys -const REG_PRECAN = 2 //Doing a Precanned Registration (Not Secure) +const REG_PRECAN = 2 //Doing a Precanned Identity (Not Secure) const REG_UID_GEN = 3 //Generating User ID const REG_PERM = 4 //Validating User Identity With Permissioning Server const REG_NODE = 5 //Registering with Nodes diff --git a/go.mod b/go.mod index 6176f5edda53c1f4f99c6289e28f15280496e803..2487cca132dfd4e22eaa97b67906f072db83b138 100644 --- a/go.mod +++ b/go.mod @@ -23,10 +23,10 @@ require ( gitlab.com/elixxir/comms v0.0.4-0.20210114174157-1306832d440b gitlab.com/elixxir/crypto v0.0.7-0.20210107184400-5c3e52a35758 gitlab.com/elixxir/ekv v0.1.4 - gitlab.com/elixxir/primitives v0.0.3-0.20210107183456-9cf6fe2de1e5 + gitlab.com/elixxir/primitives v0.0.3-0.20210127201240-6a42ad925e8a gitlab.com/xx_network/comms v0.0.4-0.20210112233928-eac8db03c397 gitlab.com/xx_network/crypto v0.0.5-0.20210107183440-804e0f8b7d22 - gitlab.com/xx_network/primitives v0.0.4-0.20210114170718-1549f24d462c + gitlab.com/xx_network/primitives v0.0.4-0.20210121231232-022320b01e08 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 // indirect diff --git a/go.sum b/go.sum index f5f678113615e8cdda98594645a7827210c2d71a..2c7a05e3a4878798243b484875367d66ee7134bb 100644 --- a/go.sum +++ b/go.sum @@ -310,6 +310,10 @@ gitlab.com/elixxir/primitives v0.0.3-0.20210106014507-bf3dfe228fa6 h1:sUqEla1uUI gitlab.com/elixxir/primitives v0.0.3-0.20210106014507-bf3dfe228fa6/go.mod h1:Ph6isHUDVjmRUd9DioyKpd8W9J52gKBiDeue4DCygXA= gitlab.com/elixxir/primitives v0.0.3-0.20210107183456-9cf6fe2de1e5 h1:50HbCJWirpX2Q+NNhIHcs0M9f45H1UJ/7LNMu81Bnn0= gitlab.com/elixxir/primitives v0.0.3-0.20210107183456-9cf6fe2de1e5/go.mod h1:Ph6isHUDVjmRUd9DioyKpd8W9J52gKBiDeue4DCygXA= +gitlab.com/elixxir/primitives v0.0.3-0.20210127194347-988bd6621899 h1:23S/mz5H4HOj2v2b33arSeYHH8FrdPAzEoImnJP91j4= +gitlab.com/elixxir/primitives v0.0.3-0.20210127194347-988bd6621899/go.mod h1:Ph6isHUDVjmRUd9DioyKpd8W9J52gKBiDeue4DCygXA= +gitlab.com/elixxir/primitives v0.0.3-0.20210127201240-6a42ad925e8a h1:ZQncDfITNE12EdJK+shh6UzHlALhNU4Zjvv4hid2krs= +gitlab.com/elixxir/primitives v0.0.3-0.20210127201240-6a42ad925e8a/go.mod h1:Ph6isHUDVjmRUd9DioyKpd8W9J52gKBiDeue4DCygXA= gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023/go.mod h1:owEcxTRl7gsoM8c3RQ5KAm5GstxrJp5tn+6JfQ4z5Hw= gitlab.com/xx_network/comms v0.0.4-0.20201130190834-365ddae56e7b/go.mod h1:YViGbRj7FjJYoaO4NpALGEd9dK/l8uUT000FEBbUTL8= gitlab.com/xx_network/comms v0.0.4-0.20201217200138-87075d5b4ffd h1:4LjS3UuBNA/AaglIJ+k1IBoxYgCWt+FM1MPYxjAFfaQ= @@ -349,6 +353,12 @@ gitlab.com/xx_network/primitives v0.0.4-0.20210106014326-691ebfca3b07 h1:ZxGp7Q0 gitlab.com/xx_network/primitives v0.0.4-0.20210106014326-691ebfca3b07/go.mod h1:cs0QlFpdMDI6lAo61lDRH2JZz+3aVkHy+QogOB6F/qc= gitlab.com/xx_network/primitives v0.0.4-0.20210114170718-1549f24d462c h1:RjDklUt70MgcVqBoJvWdBoygkizoByv6Q6DsZSqcFSI= gitlab.com/xx_network/primitives v0.0.4-0.20210114170718-1549f24d462c/go.mod h1:9imZHvYwNFobxueSvVtHneZLk9wTK7HQTzxPm+zhFhE= +gitlab.com/xx_network/primitives v0.0.4-0.20210118193646-93176e2e6925 h1:n40/5N6aXnye+QmkqKCnEEEepYw4lN9uQ/mhAyCyA3o= +gitlab.com/xx_network/primitives v0.0.4-0.20210118193646-93176e2e6925/go.mod h1:cs0QlFpdMDI6lAo61lDRH2JZz+3aVkHy+QogOB6F/qc= +gitlab.com/xx_network/primitives v0.0.4-0.20210120193504-6fb365621996 h1:ChTPjKVl3XZDsqZpaSbWT8vixiHhhcGh/ytH4feYz4A= +gitlab.com/xx_network/primitives v0.0.4-0.20210120193504-6fb365621996/go.mod h1:9imZHvYwNFobxueSvVtHneZLk9wTK7HQTzxPm+zhFhE= +gitlab.com/xx_network/primitives v0.0.4-0.20210121231232-022320b01e08 h1:NZl2gjkiSZQVls4dHys+EoE6eGIU2YBXKqLaBVuV+b0= +gitlab.com/xx_network/primitives v0.0.4-0.20210121231232-022320b01e08/go.mod h1:9imZHvYwNFobxueSvVtHneZLk9wTK7HQTzxPm+zhFhE= gitlab.com/xx_network/ring v0.0.2 h1:TlPjlbFdhtJrwvRgIg4ScdngMTaynx/ByHBRZiXCoL0= gitlab.com/xx_network/ring v0.0.2/go.mod h1:aLzpP2TiZTQut/PVHR40EJAomzugDdHXetbieRClXIM= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= diff --git a/network/message/sendCmix.go b/network/message/sendCmix.go index 4addcb7e8998f00301d0c8d9800e6e92b6c37fd8..cdc25ed105c68c9ad0b553e5758098ca9d89f45a 100644 --- a/network/message/sendCmix.go +++ b/network/message/sendCmix.go @@ -142,7 +142,7 @@ func (m *Manager) SendCMIX(msg format.Message, param params.CMIX) (id.Round, err } // Signals to the node registration thread to register a node if keys are -// missing. Registration is triggered automatically when the node is first seen, +// missing. Identity is triggered automatically when the node is first seen, // so this should on trigger on rare events. func handleMissingNodeKeys(instance *network.Instance, newNodeChan chan network.NodeGateway, nodes []*id.ID) { diff --git a/permissioning/register.go b/permissioning/register.go index f013fbd94f4e4f5af599689b07a410c02453d3dc..1a64e54798560b270ab0d62267f7b2704a2c8ae1 100644 --- a/permissioning/register.go +++ b/permissioning/register.go @@ -36,7 +36,7 @@ func register(comms registrationMessageSender, host *connect.Host, ClientReceptionRSAPubKey: string(rsa.CreatePublicKeyPem(receptionPublicKey)), }) if err != nil { - err = errors.Wrap(err, "sendRegistrationMessage: Unable to contact Registration Server!") + err = errors.Wrap(err, "sendRegistrationMessage: Unable to contact Identity Server!") return nil, nil, err } if response.Error != "" { diff --git a/storage/reception/IdentityUse.go b/storage/reception/IdentityUse.go new file mode 100644 index 0000000000000000000000000000000000000000..5a96aef576898cf072ad0bf3af612e833e820392 --- /dev/null +++ b/storage/reception/IdentityUse.go @@ -0,0 +1,63 @@ +package reception + +import ( + "github.com/pkg/errors" + "gitlab.com/elixxir/crypto/hash" + "gitlab.com/elixxir/primitives/knownRounds" + "gitlab.com/xx_network/crypto/randomness" + "gitlab.com/xx_network/primitives/id" + "io" + "math/big" + "time" +) + +type IdentityUse struct{ + Identity + + //randomly generated time to poll between + StartRequest time.Time //timestamp to request the start of bloom filters + EndRequest time.Time //timestamp to request the End of bloom filters + + // denotes if the identity is fake, in which case we do not process + // messages + Fake bool + + //rounds data + KR KnownRounds +} + +func (iu IdentityUse)SetSamplingPeriod(rng io.Reader)(IdentityUse, error){ + + //generate the seed + seed := make([]byte,32) + if _, err := rng.Read(seed);err!=nil{ + return IdentityUse{}, errors.WithMessage(err, "Failed to " + + "choose id due to rng failure") + } + + h, err := hash.NewCMixHash() + if err==nil{ + return IdentityUse{}, err + } + + //calculate the period offset + periodOffset := + randomness.RandInInterval(big.NewInt(iu.RequestMask.Nanoseconds()), + seed,h).Uint64() + iu.StartRequest = iu.StartValid.Add(-time.Duration(periodOffset)* + time.Nanosecond) + iu.EndRequest = iu.EndValid.Add(iu.RequestMask - + time.Duration(periodOffset)*time.Nanosecond) + return iu, nil +} + +type KnownRounds interface{ + Checked(rid id.Round) bool + Check(rid id.Round) + Forward(rid id.Round) + RangeUnchecked(newestRid id.Round, roundCheck func(id id.Round) bool) + RangeUncheckedMasked(mask *knownRounds.KnownRounds, + roundCheck knownRounds.RoundCheckFunc, maxChecked int) + RangeUncheckedMaskedRange(mask *knownRounds.KnownRounds, + roundCheck knownRounds.RoundCheckFunc, start, end id.Round, maxChecked int) +} \ No newline at end of file diff --git a/storage/reception/fake.go b/storage/reception/fake.go new file mode 100644 index 0000000000000000000000000000000000000000..bc72c6157b119ebe9c32626c065447c3985fd7d4 --- /dev/null +++ b/storage/reception/fake.go @@ -0,0 +1,43 @@ +package reception + +import ( + "github.com/pkg/errors" + "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/id/ephemeral" + "io" + "time" +) + +func generateFakeIdentity(rng io.Reader, idSize uint)(IdentityUse, error){ + randIDbytes := make([]byte, id.ArrIDLen-1) + if _, err := rng.Read(randIDbytes); err!=nil{ + return IdentityUse{}, errors.WithMessage(err, "failed to " + + "generate a random identity when none is available") + } + + randID := &id.ID{} + copy(randID[:id.ArrIDLen-1], randIDbytes) + randID.SetType(id.User) + + ephID, start, end, err := ephemeral.GetId(randID, idSize, + time.Now().UnixNano()) + if err!=nil{ + return IdentityUse{}, errors.WithMessage(err, "failed to " + + "generate an ephemral ID for random identity when none is " + + "available") + } + + return IdentityUse{ + Identity: Identity{ + EphId: ephID, + Source: randID, + End: end, + ExtraChecks: 0, + StartValid: start, + EndValid: end, + RequestMask: 24 * time.Hour, + Ephemeral: true, + }, + Fake: true, + }, nil +} diff --git a/storage/reception/identity.go b/storage/reception/identity.go new file mode 100644 index 0000000000000000000000000000000000000000..7ec0a33a33dfe91dd1b3bd17c1e532a71c5e16e6 --- /dev/null +++ b/storage/reception/identity.go @@ -0,0 +1,85 @@ +package reception + +import ( + "encoding/json" + "github.com/pkg/errors" + "gitlab.com/elixxir/client/storage/versioned" + "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/id/ephemeral" + "time" +) + +const identityStorageKey = "IdentityStorage" +const identityStorageVersion = 0 + +type Identity struct{ + //identity + EphId ephemeral.Id + Source *id.ID + + //usage variables + End time.Time // timestamp when active polling will stop + ExtraChecks uint // number of extra checks executed as active + // after the id exits active + + //polling parameters + StartValid time.Time // timestamp when the ephID begins being valid + EndValid time.Time // timestamp when the ephID stops being valid + RequestMask time.Duration // amount of extra time requested for the poll + // in order to mask the exact valid time for + // the id + + //makes the identity not store on disk + Ephemeral bool +} + +func loadIdentity(kv *versioned.KV)(Identity, error){ + obj, err := kv.Get(identityStorageKey) + if err!=nil{ + return Identity{}, errors.WithMessage(err, "Failed to load Identity") + } + + r := Identity{} + err = json.Unmarshal(obj.Data, &r) + if err!=nil{ + return Identity{}, errors.WithMessage(err, "Failed to unmarshal Identity") + } + return r, nil +} + + +func (i Identity)store(kv *versioned.KV)error{ + //marshal the registration + regStr, err := json.Marshal(&i) + if err!=nil{ + return errors.WithMessage(err, "Failed to marshal Identity") + } + + // Create versioned object with data + obj := &versioned.Object{ + Version: identityStorageVersion, + Timestamp: time.Now(), + Data: regStr, + } + + //store the data + err = kv.Set(identityStorageKey, obj) + if err!=nil{ + return errors.WithMessage(err, "Failed to store Identity") + } + + return nil +} + +func (i Identity)delete(kv *versioned.KV)error{ + return kv.Delete(identityStorageKey) +} + +func (i Identity)calculateKrSize()int{ + return int(i.EndValid.Sub(i.StartValid).Seconds()+1)*maxRoundsPerSecond +} + +func (i *Identity)String()string{ + return string(i.EphId.Int64()) + " " + i.String() +} + diff --git a/storage/reception/identity_test.go b/storage/reception/identity_test.go new file mode 100644 index 0000000000000000000000000000000000000000..2117f731f24b3a1ca5059879df871b094933820d --- /dev/null +++ b/storage/reception/identity_test.go @@ -0,0 +1,68 @@ +package reception + +import ( + "gitlab.com/elixxir/client/storage/versioned" + "gitlab.com/elixxir/ekv" + "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/id/ephemeral" + "reflect" + "testing" + "time" +) + +func TestIdentityEncodeDecode(t *testing.T) { + + kv := versioned.NewKV(make(ekv.Memstore)) + r := Identity{ + EphId: ephemeral.Id{}, + Source: &id.Permissioning, + End: time.Now().Round(0), + ExtraChecks: 12, + StartValid: time.Now().Round(0), + EndValid: time.Now().Round(0), + RequestMask: 2*time.Hour, + Ephemeral: false, + } + err := r.store(kv) + if err!=nil{ + t.Errorf("Failed to store: %s", err) + } + + rLoad, err := loadIdentity(kv) + if err!=nil{ + t.Errorf("Failed to load: %s", err) + } + + if !reflect.DeepEqual(r, rLoad){ + t.Errorf("The two registrations are not the same\n saved: %+v\n loaded: %+v", r, rLoad) + } +} + +func TestIdentityDelete(t *testing.T) { + + kv := versioned.NewKV(make(ekv.Memstore)) + r := Identity{ + EphId: ephemeral.Id{}, + Source: &id.Permissioning, + End: time.Now().Round(0), + ExtraChecks: 12, + StartValid: time.Now().Round(0), + EndValid: time.Now().Round(0), + RequestMask: 2 * time.Hour, + Ephemeral: false, + } + err := r.store(kv) + if err != nil { + t.Errorf("Failed to store: %s", err) + } + + err = r.delete(kv) + if err != nil { + t.Errorf("Failed to delete: %s", err) + } + + _, err = loadIdentity(kv) + if err == nil { + t.Errorf("Load after delete succeded") + } +} diff --git a/storage/reception/registration.go b/storage/reception/registration.go new file mode 100644 index 0000000000000000000000000000000000000000..f010b46b05e0d61b7baf929f97f613412b904b53 --- /dev/null +++ b/storage/reception/registration.go @@ -0,0 +1,115 @@ +package reception + +import ( + "github.com/pkg/errors" + "gitlab.com/elixxir/client/storage/utility" + "gitlab.com/elixxir/client/storage/versioned" + "gitlab.com/elixxir/primitives/knownRounds" + "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/id/ephemeral" + "time" + +) + +const maxRoundsPerSecond = 100 +const knownRoundsStorageKey = "krStorage" + + +type registration struct{ + Identity + knownRounds *knownRounds.KnownRounds + knownRoundsStorage *utility.KnownRounds + kv *versioned.KV +} + +func newRegistration(reg Identity, kv *versioned.KV)(*registration, error){ + //round the times to remove the monotic clocks for future saving + reg.StartValid = reg.StartValid.Round(0) + reg.EndValid = reg.EndValid.Round(0) + reg.End = reg.End.Round(0) + + now := time.Now() + + //do edge checks to determine if the identity is valid + if now.After(reg.End) && reg.ExtraChecks<1{ + return nil, errors.New("Cannot create a registration for an " + + "identity which has expired") + } + + //set the prefix + kv = kv.Prefix(regPrefix(reg.EphId, reg.Source)) + + + r := ®istration{ + Identity: reg, + knownRounds: knownRounds.NewKnownRound(reg.calculateKrSize()), + kv: kv, + } + + //if this isn't ephemeral, store everything + if !reg.Ephemeral{ + //store known rounds + var err error + r.knownRoundsStorage, err = utility.NewKnownRounds(kv, knownRoundsStorageKey, r.knownRounds) + if err!=nil{ + return nil, errors.WithMessage(err, "failed to store known rounds") + } + //store the registration + if err = reg.store(kv); err!=nil{ + return nil, errors.WithMessage(err, "failed to store registration") + } + } + + return r, nil +} + +func loadRegistration(EphId ephemeral.Id, Source *id.ID, kv *versioned.KV)(*registration, error){ + kv = kv.Prefix(regPrefix(EphId, Source)) + + reg, err := loadIdentity(kv) + if err!=nil{ + return nil, errors.WithMessagef(err, "Failed to load identity " + + "for %s", regPrefix(EphId, Source)) + } + + kr, err := utility.LoadKnownRounds(kv,knownRoundsStorageKey, reg.calculateKrSize()) + if err!=nil{ + return nil, errors.WithMessagef(err, "Failed to load known " + + "rounds for %s", regPrefix(EphId, Source)) + } + + r := ®istration{ + Identity: reg, + knownRoundsStorage: kr, + kv: kv, + } + + return r, nil +} + + +func (r *registration)Delete()error{ + if !r.Ephemeral{ + if err:=r.knownRoundsStorage.Delete(); err!=nil{ + return errors.WithMessagef(err, "Failed to delete " + + "registration known rounds %s", r) + } + if err:=r.delete(r.kv); err!=nil{ + return errors.WithMessagef(err, "Failed to delete " + + "registration public data %s", r) + } + } + return nil +} + +func (r registration)getKR()KnownRounds{ + if r.Ephemeral{ + return r.knownRounds + }else{ + return r.knownRoundsStorage + } +} + +func regPrefix(EphId ephemeral.Id, Source *id.ID)string{ + return "receptionRegistration_" + string(EphId.Int64()) + Source.String() +} \ No newline at end of file diff --git a/storage/reception/store.go b/storage/reception/store.go new file mode 100644 index 0000000000000000000000000000000000000000..36353924eb21c2dbd5a3e4797a40596a11494d25 --- /dev/null +++ b/storage/reception/store.go @@ -0,0 +1,303 @@ +package reception + +import ( + "bytes" + "encoding/json" + "github.com/pkg/errors" + jww "github.com/spf13/jwalterweatherman" + "gitlab.com/elixxir/client/storage/versioned" + "gitlab.com/elixxir/crypto/hash" + "gitlab.com/xx_network/crypto/randomness" + "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/id/ephemeral" + "io" + "math/big" + "strconv" + "sync" + "time" +) + +const receptionPrefix = "reception" +const receptionStoreStorageKey = "receptionStoreKey" +const receptionStoreStorageVersion = 0 +const receptionIDSizeStorageKey = "receptionIDSizeKey" +const receptionIDSizeStorageVersion = 0 +const defaultIDSize = 12 + +type Store struct{ + // identities which are being actively checked + active []*registration + idSize int + + kv *versioned.KV + + mux sync.Mutex +} + +type storedReference struct { + Eph ephemeral.Id + Source *id.ID +} + +//creates a new reception store. It starts empty +func NewStore(kv *versioned.KV)*Store{ + kv = kv.Prefix(receptionPrefix) + s := &Store{ + active: make([]*registration, 0), + idSize: defaultIDSize, + kv: kv, + } + + //store the empty list + if err := s.save(); err!=nil{ + jww.FATAL.Panicf("Failed to save new reception store: %+v", err) + } + + //update the size so queries can be made + s.UpdateIDSize(defaultIDSize) + + return s +} + +func LoadStore(kv *versioned.KV)*Store{ + kv = kv.Prefix(receptionPrefix) + s := &Store{ + kv: kv, + } + + // Load the versioned object for the reception list + vo, err := kv.Get(receptionStoreStorageKey) + if err != nil { + jww.FATAL.Panicf("Failed to get the reception storage list: %+v", + err) + } + + identities := make([]storedReference, len(s.active)) + err = json.Unmarshal(vo.Data, &identities) + if err!=nil{ + jww.FATAL.Panicf("Failed to unmarshal the reception storage " + + "list: %+v", err) + } + + s.active = make([]*registration, len(identities)) + for i, sr := range identities{ + s.active[i], err = loadRegistration(sr.Eph, sr.Source, s.kv) + if err!=nil{ + jww.FATAL.Panicf("Failed to load registration for %s: %+v", + regPrefix(sr.Eph, sr.Source), err) + } + } + + //load the ephmemeral ID length + vo, err = kv.Get(receptionIDSizeStorageKey) + if err != nil { + jww.FATAL.Panicf("Failed to get the reception id size: %+v", + err) + } + + if s.idSize, err = strconv.Atoi(string(vo.Data)); err!=nil{ + jww.FATAL.Panicf("Failed to unmarshal the reception id size: %+v", + err) + } + + return s +} + +func (s *Store) save()error{ + identities := make([]storedReference, len(s.active)) + i := 0 + for _, reg := range s.active{ + if !reg.Ephemeral{ + identities[i] = storedReference{ + Eph: reg.EphId, + Source: reg.Source, + } + i++ + } + } + identities = identities[:i] + + data, err := json.Marshal(&identities) + if err!=nil{ + return errors.WithMessage(err, "failed to store reception " + + "store") + } + + // Create versioned object with data + obj := &versioned.Object{ + Version: receptionStoreStorageVersion, + Timestamp: time.Now(), + Data: data, + } + + err = s.kv.Set(receptionStoreStorageKey, obj) + if err!=nil{ + return errors.WithMessage(err, "Failed to store reception store") + } + + return nil +} + +func (s *Store)GetIdentity(rng io.Reader)(IdentityUse, error){ + s.mux.Lock() + defer s.mux.Unlock() + + now := time.Now() + + //remove any now expired identities + s.prune(now) + + var identity IdentityUse + var err error + + // if the list is empty, we return a randomly generated identity to poll + // with so we can continue tracking the network and to further obfuscate + // network identities + if len(s.active)==0{ + identity, err = generateFakeIdentity(rng, uint(s.idSize)) + if err!=nil{ + jww.FATAL.Panicf("Failed to generate a new ID when none " + + "available: %+v", err) + } + }else{ + identity, err = s.selectIdentity(rng, now) + if err!=nil{ + jww.FATAL.Panicf("Failed to select an id: %+v", err) + } + } + + //calculate the sampling period + identity, err = identity.SetSamplingPeriod(rng) + if err!=nil{ + jww.FATAL.Panicf("Failed to caluclate the sampling period: " + + "%+v", err) + } + + return identity, nil +} + +func (s *Store)AddIdentity(identity Identity)error { + s.mux.Lock() + defer s.mux.Unlock() + + reg, err := newRegistration(identity, s.kv) + if err!=nil{ + return errors.WithMessage(err,"failed to add new identity to " + + "reception store") + } + + s.active = append(s.active, reg) + if !identity.Ephemeral{ + if err := s.save(); err!=nil{ + jww.FATAL.Panicf("Failed to save reception store after identity " + + "addition") + } + } + + return nil +} + +func (s *Store)RemoveIdentity(ephID ephemeral.Id)bool { + s.mux.Lock() + defer s.mux.Unlock() + + for i:=0;i<len(s.active);i++{ + inQuestion := s.active[i] + if bytes.Equal(inQuestion.EphId[:],ephID[:]){ + s.active = append(s.active[:i], s.active[i+1:]...) + err := inQuestion.Delete() + if err!=nil{ + jww.FATAL.Panicf("Failed to delete identity %s") + } + if !inQuestion.Ephemeral{ + if err := s.save(); err!=nil{ + jww.FATAL.Panicf("Failed to save reception store after " + + "identity removal") + } + } + + return true + } + } + + return false +} + +func (s *Store)UpdateIDSize(idSize uint){ + s.mux.Lock() + defer s.mux.Unlock() + s.idSize = int(idSize) + //store the id size + obj := &versioned.Object{ + Version: receptionIDSizeStorageVersion, + Timestamp: time.Now(), + Data: []byte(strconv.Itoa(s.idSize)), + } + + err := s.kv.Set(receptionIDSizeStorageKey, obj) + if err!=nil{ + jww.FATAL.Panicf("Failed to store reception ID size: %+v", err) + } +} + +func (s *Store)prune(now time.Time) { + lengthBefore := len(s.active) + + //prune the list + for i:=0;i<len(s.active);i++{ + inQuestion := s.active[i] + if now.After(inQuestion.End) && inQuestion.ExtraChecks ==0{ + if err := inQuestion.Delete(); err!=nil{ + jww.ERROR.Printf("Failed to delete Identity for %s: " + + "%+v", inQuestion, err) + } + + s.active = append(s.active[:i-1], s.active[i:]...) + + i-- + } + } + + //save the list if it changed + if lengthBefore!=len(s.active){ + if err := s.save(); err!=nil{ + jww.FATAL.Panicf("Failed to store reception storage") + } + } +} + +func (s *Store)selectIdentity(rng io.Reader, now time.Time)(IdentityUse, error) { + + //choose a member from the list + var selected *registration + + if len(s.active)==1{ + selected= s.active[0] + }else{ + + seed := make([]byte,32) + if _, err := rng.Read(seed);err!=nil{ + return IdentityUse{}, errors.WithMessage(err, "Failed to " + + "choose id due to rng failure") + } + + h, err := hash.NewCMixHash() + if err==nil{ + return IdentityUse{}, err + } + + selectedNum := randomness.RandInInterval( + big.NewInt(int64(len(s.active)-1)),seed,h) + selected = s.active[selectedNum.Uint64()] + } + + if now.After(selected.End){ + selected.ExtraChecks-- + } + + return IdentityUse{ + Identity: selected.Identity, + Fake: false, + KR: selected.getKR(), + }, nil +} \ No newline at end of file diff --git a/storage/regStatus.go b/storage/regStatus.go index 52f74dd10bf98631892237b1820ba31b105c8ecd..ec18a0cfcb92aaa9c154f23528a40a96f202273f 100644 --- a/storage/regStatus.go +++ b/storage/regStatus.go @@ -27,7 +27,7 @@ const ( UDBComplete RegistrationStatus = 30000 // Set upon completion of RegisterWithUdb ) -// stringer for Registration Status +// stringer for Identity Status func (rs RegistrationStatus) String() string { switch rs { case NotStarted: @@ -35,9 +35,9 @@ func (rs RegistrationStatus) String() string { case KeyGenComplete: return "Key Generation Complete" case PermissioningComplete: - return "Permissioning Registration Complete" + return "Permissioning Identity Complete" case UDBComplete: - return "User Discovery Registration Complete" + return "User Discovery Identity Complete" default: return fmt.Sprintf("Unknown registration state %v", uint32(rs)) } diff --git a/storage/user/regValidationSig.go b/storage/user/regValidationSig.go index 215526936b02440a3ac6a8c84d2ee9b6d96a135b..a64b33d4d713acefe6dad14eb8d1c3a056188d66 100644 --- a/storage/user/regValidationSig.go +++ b/storage/user/regValidationSig.go @@ -17,7 +17,7 @@ const currentRegValidationSigVersion = 0 const transmissionRegValidationSigKey = "transmissionRegistrationValidationSignature" const receptionRegValidationSigKey = "receptionRegistrationValidationSignature" -// Returns the transmission Registration Validation Signature stored in RAM. May return +// Returns the transmission Identity Validation Signature stored in RAM. May return // nil of no signature is stored func (u *User) GetTransmissionRegistrationValidationSignature() []byte { u.rvsMux.RLock() @@ -25,7 +25,7 @@ func (u *User) GetTransmissionRegistrationValidationSignature() []byte { return u.transmissionRegValidationSig } -// Returns the reception Registration Validation Signature stored in RAM. May return +// Returns the reception Identity Validation Signature stored in RAM. May return // nil of no signature is stored func (u *User) GetReceptionRegistrationValidationSignature() []byte { u.rvsMux.RLock() @@ -33,7 +33,7 @@ func (u *User) GetReceptionRegistrationValidationSignature() []byte { return u.receptionRegValidationSig } -// Loads the transmission Registration Validation Signature if it exists in the ekv +// Loads the transmission Identity Validation Signature if it exists in the ekv func (u *User) loadTransmissionRegistrationValidationSignature() { u.rvsMux.Lock() obj, err := u.kv.Get(transmissionRegValidationSigKey) @@ -43,7 +43,7 @@ func (u *User) loadTransmissionRegistrationValidationSignature() { u.rvsMux.Unlock() } -// Loads the reception Registration Validation Signature if it exists in the ekv +// Loads the reception Identity Validation Signature if it exists in the ekv func (u *User) loadReceptionRegistrationValidationSignature() { u.rvsMux.Lock() obj, err := u.kv.Get(receptionRegValidationSigKey) @@ -53,7 +53,7 @@ func (u *User) loadReceptionRegistrationValidationSignature() { u.rvsMux.Unlock() } -// Sets the Registration Validation Signature if it is not set and stores it in +// Sets the Identity Validation Signature if it is not set and stores it in // the ekv func (u *User) SetTransmissionRegistrationValidationSignature(b []byte) { u.rvsMux.Lock() @@ -61,7 +61,7 @@ func (u *User) SetTransmissionRegistrationValidationSignature(b []byte) { //check if the signature already exists if u.transmissionRegValidationSig != nil { - jww.FATAL.Panicf("cannot overwrite existing transmission Registration Validation Signature") + jww.FATAL.Panicf("cannot overwrite existing transmission Identity Validation Signature") } obj := &versioned.Object{ @@ -72,14 +72,14 @@ func (u *User) SetTransmissionRegistrationValidationSignature(b []byte) { err := u.kv.Set(transmissionRegValidationSigKey, obj) if err != nil { - jww.FATAL.Panicf("Failed to store the transmission Registration Validation "+ + jww.FATAL.Panicf("Failed to store the transmission Identity Validation "+ "Signature: %s", err) } u.transmissionRegValidationSig = b } -// Sets the Registration Validation Signature if it is not set and stores it in +// Sets the Identity Validation Signature if it is not set and stores it in // the ekv func (u *User) SetReceptionRegistrationValidationSignature(b []byte) { u.rvsMux.Lock() @@ -87,7 +87,7 @@ func (u *User) SetReceptionRegistrationValidationSignature(b []byte) { //check if the signature already exists if u.receptionRegValidationSig != nil { - jww.FATAL.Panicf("cannot overwrite existing reception Registration Validation Signature") + jww.FATAL.Panicf("cannot overwrite existing reception Identity Validation Signature") } obj := &versioned.Object{ @@ -98,7 +98,7 @@ func (u *User) SetReceptionRegistrationValidationSignature(b []byte) { err := u.kv.Set(receptionRegValidationSigKey, obj) if err != nil { - jww.FATAL.Panicf("Failed to store the reception Registration Validation "+ + jww.FATAL.Panicf("Failed to store the reception Identity Validation "+ "Signature: %s", err) } diff --git a/storage/utility/knownRounds.go b/storage/utility/knownRounds.go index 767ad917c4e57f7e8040deb58713e069fd2b6596..72f4833d7158483fb88c881434a7ed8f4009852b 100644 --- a/storage/utility/knownRounds.go +++ b/storage/utility/knownRounds.go @@ -35,10 +35,10 @@ type KnownRounds struct { // NewKnownRounds creates a new empty KnownRounds and saves it to the passed // in key value store at the specified key. An error is returned on an // unsuccessful save. -func NewKnownRounds(kv *versioned.KV, key string, size int) (*KnownRounds, error) { +func NewKnownRounds(kv *versioned.KV, key string, known *knownRounds.KnownRounds) (*KnownRounds, error) { // Create new empty struct kr := &KnownRounds{ - rounds: knownRounds.NewKnownRound(size), + rounds: known, kv: kv.Prefix(knownRoundsPrefix), key: key, } @@ -107,6 +107,15 @@ func (kr *KnownRounds) load() error { return nil } +// Deletes a known rounds object from disk and memory +func (kr *KnownRounds) Delete() error { + err := kr.kv.Delete(kr.key) + if err != nil { + return err + } + return nil +} + // Checked determines if the round has been checked. func (kr *KnownRounds) Checked(rid id.Round) bool { kr.mux.RLock() @@ -158,7 +167,7 @@ func (kr *KnownRounds) RangeUnchecked(newestRid id.Round, // RangeUncheckedMasked checks rounds based off the provided mask. func (kr *KnownRounds) RangeUncheckedMasked(mask *knownRounds.KnownRounds, - roundCheck func(id id.Round) bool, maxChecked int) { + roundCheck knownRounds.RoundCheckFunc, maxChecked int) { kr.mux.Lock() defer kr.mux.Unlock() @@ -169,3 +178,17 @@ func (kr *KnownRounds) RangeUncheckedMasked(mask *knownRounds.KnownRounds, jww.FATAL.Panicf("Error saving list of checked rounds: %v", err) } } + +// RangeUncheckedMasked checks rounds based off the provided mask. +func (kr *KnownRounds) RangeUncheckedMaskedRange(mask *knownRounds.KnownRounds, + roundCheck knownRounds.RoundCheckFunc, start, end id.Round, maxChecked int) { + kr.mux.Lock() + defer kr.mux.Unlock() + + kr.rounds.RangeUncheckedMaskedRange(mask, roundCheck, start, end, maxChecked) + + err := kr.save() + if err != nil { + jww.FATAL.Panicf("Error saving list of checked rounds: %v", err) + } +} diff --git a/storage/utility/knownRounds_test.go b/storage/utility/knownRounds_test.go index 73f0cb5a38d2ef39b33d57ea1ae2892d335d015c..653025dbb46282006abdafdbf6733e591ade0705 100644 --- a/storage/utility/knownRounds_test.go +++ b/storage/utility/knownRounds_test.go @@ -28,7 +28,8 @@ func TestNewKnownRounds(t *testing.T) { } // Create new KnownRounds - kr, err := NewKnownRounds(rootKv, expectedKR.key, size) + k := knownRounds.NewKnownRound(size) + kr, err := NewKnownRounds(rootKv, expectedKR.key, k) if err != nil { t.Errorf("NewKnownRounds() returned an error."+ "\n\texpected: %v\n\treceived: %v", nil, err) @@ -154,7 +155,8 @@ func TestKnownRounds_save(t *testing.T) { // } func TestKnownRounds_Smoke(t *testing.T) { - kr, err := NewKnownRounds(versioned.NewKV(make(ekv.Memstore)), "testKey", 10) + k := knownRounds.NewKnownRound(10) + kr, err := NewKnownRounds(versioned.NewKV(make(ekv.Memstore)), "testKey", k) if err != nil { t.Fatalf("Failed to create new KnownRounds: %v", err) } diff --git a/ud/register.go b/ud/register.go index c54e768ec667104547a9258090945dfb5cb1aa4f..3afd284bb842ccd8182689c181c57e2bf0d5de6f 100644 --- a/ud/register.go +++ b/ud/register.go @@ -20,7 +20,7 @@ type registerUserComms interface { // network signatures are malformed or if the username is taken. Usernames cannot // be changed after registration at this time. Will fail if the user is already // registered. -// Registration does not go over cmix, it occurs over normal communications +// Identity does not go over cmix, it occurs over normal communications func (m *Manager) Register(username string) error { jww.INFO.Printf("ud.Register(%s)", username) return m.register(username, m.comms)