// CreateUser inserts User object into a database, updates creation time and assigns UID func (u UsersObjMapper) Create(user *types.User, private interface{}) (*types.User, error) { user.SetUid(GetUid()) err, _ := adaptr.UserCreate(user) if err != nil { return nil, err } // Create user's subscription to 'me' && 'find'. Theese topics are ephemeral, the topic object need not to be inserted. err = Subs.Create( &types.Subscription{ ObjHeader: types.ObjHeader{CreatedAt: user.CreatedAt}, User: user.Id, Topic: user.Uid().UserId(), ModeWant: types.ModeSelf, ModeGiven: types.ModeSelf, Private: private, }, &types.Subscription{ ObjHeader: types.ObjHeader{CreatedAt: user.CreatedAt}, User: user.Id, Topic: user.Uid().FndName(), ModeWant: types.ModeSelf, ModeGiven: types.ModeSelf, Private: nil, }) if err != nil { // Best effort to delete incomplete user record. Orphaned user records are not a problem. // They just take up space. adaptr.UserDelete(user.Uid(), true) return nil, err } return user, nil }
// CreateUser inserts User object into a database, updates creation time and assigns UID func (u UsersObjMapper) Create(user *types.User, scheme, secret string, private interface{}) (*types.User, error) { if scheme == "basic" { if splitAt := strings.Index(secret, ":"); splitAt > 0 { user.InitTimes() user.Username = secret[:splitAt] var err error user.Passhash, err = bcrypt.GenerateFromPassword([]byte(secret[splitAt+1:]), bcrypt.DefaultCost) if err != nil { return nil, err } // TODO(gene): maybe have some additional handling of duplicate user name error err, _ = adaptr.UserCreate(user) user.Passhash = nil if err != nil { return nil, err } // Create user's subscription to !me. The !me topic is ephemeral, the topic object need not to be inserted. err = Subs.Create(&types.Subscription{ ObjHeader: types.ObjHeader{CreatedAt: user.CreatedAt}, User: user.Id, Topic: user.Uid().UserId(), ModeWant: types.ModeSelf, ModeGiven: types.ModeSelf, Private: private, }) if err != nil { return nil, err } return user, nil } else { return nil, errors.New("store: invalid format of secret") } } return nil, errors.New("store: unknown authentication scheme '" + scheme + "'") }
func gen_rethink(reset bool, dbsource string, data *Data) { var err error log.Println("Opening DB...") err = store.Open("rethinkdb", dbsource) if err != nil { log.Fatal("Failed to connect to DB: ", err) } defer store.Close() log.Println("Initializing DB...") err = store.InitDb(reset) if err != nil { if strings.Contains(err.Error(), " already exists") { log.Println("DB already exists, NOT reinitializing") } else { log.Fatal("Failed to init DB: ", err) } } else { log.Println("DB successfully initialized") } if data.Users == nil { log.Println("No data provided, stopping") return } nameIndex := make(map[string]string, len(data.Users)) log.Println("Generating users...") for _, uu := range data.Users { if uu["createdAt"] != nil { } user := types.User{ State: int(uu["state"].(float64)), Username: uu["username"].(string), Access: types.DefaultAccess{ Auth: types.ModePublic, Anon: types.ModeNone, }, Public: uu["public"], } user.CreatedAt = getCreatedTime(uu["createdAt"]) // store.Users.Create will subscribe user to !me topic but won't create a !me topic if _, err := store.Users.Create(&user, "basic", uu["username"].(string)+":"+uu["passhash"].(string), uu["private"]); err != nil { log.Fatal(err) } nameIndex[user.Username] = user.Id log.Printf("Created user '%s' as %s (%d)", user.Username, user.Id, user.Uid()) } log.Println("Generating group topics...") for _, gt := range data.Grouptopics { name := genTopicName() nameIndex[gt["name"].(string)] = name topic := &types.Topic{Name: name, Public: gt["public"]} var owner types.Uid if gt["owner"] != nil { owner = types.ParseUid(nameIndex[gt["owner"].(string)]) topic.GiveAccess(owner, types.ModeFull, types.ModeFull) } topic.CreatedAt = getCreatedTime(gt["createdAt"]) if err = store.Topics.Create(topic, owner, gt["private"]); err != nil { log.Fatal(err) } log.Printf("Created topic '%s' as %s", gt["name"].(string), name) } log.Println("Generating P2P subscriptions...") p2pIndex := map[string][]map[string]interface{}{} for _, ss := range data.Subscriptions { u1 := ss["user"].(string) u2 := ss["topic"].(string) if u2[0] == '*' { // skip group topics continue } var pair string var idx int if u1 < u2 { pair = u1 + ":" + u2 idx = 0 } else { pair = u2 + ":" + u1 idx = 1 } if _, ok := p2pIndex[pair]; !ok { p2pIndex[pair] = make([]map[string]interface{}, 2) } p2pIndex[pair][idx] = ss } log.Printf("Collected p2p pairs: %d\n", len(p2pIndex)) for pair, subs := range p2pIndex { uid1 := types.ParseUid(nameIndex[subs[0]["user"].(string)]) uid2 := types.ParseUid(nameIndex[subs[1]["user"].(string)]) topic := uid1.P2PName(uid2) created0 := getCreatedTime(subs[0]["createdAt"]) created1 := getCreatedTime(subs[1]["createdAt"]) var s0want, s0given, s1want, s1given types.AccessMode if err := s0want.UnmarshalText([]byte(subs[0]["modeWant"].(string))); err != nil { log.Fatal(err) } if err := s0given.UnmarshalText([]byte(subs[0]["modeHave"].(string))); err != nil { log.Fatal(err) } if err := s1want.UnmarshalText([]byte(subs[1]["modeWant"].(string))); err != nil { log.Fatal(err) } if err := s1given.UnmarshalText([]byte(subs[1]["modeHave"].(string))); err != nil { log.Fatal(err) } log.Printf("Processing %s (%s), %s, %s", pair, topic, uid1.String(), uid2.String()) err := store.Topics.CreateP2P( &types.Subscription{ ObjHeader: types.ObjHeader{CreatedAt: created0}, User: uid1.String(), Topic: topic, ModeWant: s0want, ModeGiven: s0given, Private: subs[0]["private"]}, &types.Subscription{ ObjHeader: types.ObjHeader{CreatedAt: created1}, User: uid2.String(), Topic: topic, ModeWant: s1want, ModeGiven: s1given, Private: subs[1]["private"]}) if err != nil { log.Fatal(err) } } log.Println("Generating group subscriptions...") for _, ss := range data.Subscriptions { u1 := nameIndex[ss["user"].(string)] u2 := nameIndex[ss["topic"].(string)] var want, given types.AccessMode if err := want.UnmarshalText([]byte(ss["modeWant"].(string))); err != nil { log.Fatal(err) } if err := given.UnmarshalText([]byte(ss["modeHave"].(string))); err != nil { log.Fatal(err) } // Define topic name name := u2 if !types.ParseUid(u2).IsZero() { // skip p2p subscriptions continue } log.Printf("Sharing '%s' with '%s'", ss["topic"].(string), ss["user"].(string)) if err = store.Subs.Create(&types.Subscription{ ObjHeader: types.ObjHeader{CreatedAt: getCreatedTime(ss["createdAt"])}, User: u1, Topic: name, ModeWant: want, ModeGiven: given, Private: ss["private"]}); err != nil { log.Fatal(err) } } log.Println("Generating messages...") rand.Seed(time.Now().UnixNano()) seqIds := map[string]int{} var oldFrom types.Uid var oldTopic string toInsert := 80 // Starting 4 days ago timestamp := time.Now().UTC().Round(time.Millisecond).Add(time.Second * time.Duration(-3600*24*4)) for i := 0; i < toInsert; i++ { sub := data.Subscriptions[rand.Intn(len(data.Subscriptions))] topic := nameIndex[sub["topic"].(string)] from := types.ParseUid(nameIndex[sub["user"].(string)]) if topic == oldTopic && from == oldFrom { toInsert++ continue } oldTopic, oldFrom = topic, from if uid := types.ParseUid(topic); !uid.IsZero() { topic = uid.P2PName(from) } seqIds[topic]++ seqId := seqIds[topic] str := data.Messages[rand.Intn(len(data.Messages))] // Max time between messages is 2 hours, averate - 1 hour, time is increasing as seqId increases timestamp = timestamp.Add(time.Second * time.Duration(rand.Intn(3600*2))) msg := types.Message{ ObjHeader: types.ObjHeader{CreatedAt: timestamp}, SeqId: seqId, Topic: topic, From: from.String(), Content: str} if err = store.Messages.Save(&msg); err != nil { log.Fatal(err) } log.Printf("Message %d at %v to '%s' '%s'", msg.SeqId, msg.CreatedAt, topic, str) } }
// Account creation func (s *Session) acc(msg *ClientComMessage) { if s.ver == 0 { s.queueOut(ErrCommandOutOfSequence(msg.Acc.Id, "", msg.timestamp)) return } if msg.Acc.Auth == nil { s.queueOut(ErrMalformed(msg.Acc.Id, "", msg.timestamp)) return } else if len(msg.Acc.Auth) == 0 { s.queueOut(ErrAuthUnknownScheme(msg.Acc.Id, "", msg.timestamp)) return } if msg.Acc.User == "new" { // Request to create a new account for _, auth := range msg.Acc.Auth { if auth.Scheme == "basic" { var private interface{} var user types.User if msg.Acc.Desc != nil { user.Access.Auth = DEFAULT_AUTH_ACCESS user.Access.Anon = DEFAULT_ANON_ACCESS if msg.Acc.Desc.DefaultAcs != nil { if msg.Acc.Desc.DefaultAcs.Auth != "" { user.Access.Auth.UnmarshalText([]byte(msg.Acc.Desc.DefaultAcs.Auth)) } if msg.Acc.Desc.DefaultAcs.Anon != "" { user.Access.Anon.UnmarshalText([]byte(msg.Acc.Desc.DefaultAcs.Anon)) } } if !isNullValue(msg.Acc.Desc.Public) { user.Public = msg.Acc.Desc.Public } if !isNullValue(msg.Acc.Desc.Private) { private = msg.Acc.Desc.Private } } _, err := store.Users.Create(&user, private) if err != nil { if err.Error() == "duplicate credential" { s.queueOut(ErrDuplicateCredential(msg.Acc.Id, "", msg.timestamp)) } else { s.queueOut(ErrUnknown(msg.Acc.Id, "", msg.timestamp)) } return } reply := NoErrCreated(msg.Acc.Id, "", msg.timestamp) desc := &MsgTopicDesc{ CreatedAt: &user.CreatedAt, UpdatedAt: &user.UpdatedAt, DefaultAcs: &MsgDefaultAcsMode{ Auth: user.Access.Auth.String(), Anon: user.Access.Anon.String()}, Public: user.Public, Private: private} reply.Ctrl.Params = map[string]interface{}{ "uid": user.Uid().UserId(), "desc": desc, } s.queueOut(NoErr(msg.Acc.Id, "", msg.timestamp)) } else { s.queueOut(ErrAuthUnknownScheme(msg.Acc.Id, "", msg.timestamp)) return } } } else if !s.uid.IsZero() { // Request to change auth of an existing account. Only basic auth is currently supported for _, auth := range msg.Acc.Auth { if auth.Scheme == "basic" { if err := store.Users.ChangeAuthCredential(s.uid, auth.Scheme, string(auth.Secret)); err != nil { s.queueOut(ErrUnknown(msg.Acc.Id, "", msg.timestamp)) return } s.queueOut(NoErr(msg.Acc.Id, "", msg.timestamp)) } else { s.queueOut(ErrAuthUnknownScheme(msg.Acc.Id, "", msg.timestamp)) return } } } else { // session is not authenticated and this is not an attempt to create a new account s.queueOut(ErrPermissionDenied(msg.Acc.Id, "", msg.timestamp)) return } }