feat: migrate IM identity and snowflake primary keys
This commit is contained in:
+40
-85
@@ -73,31 +73,47 @@ func replyCreateUser(s *Session, msg *ClientComMessage, rec *auth.Rec) {
|
||||
user.State = state
|
||||
}
|
||||
|
||||
// Ensure tags are unique and not restricted.
|
||||
if tags := normalizeTags(msg.Acc.Tags, globals.maxTagCount); tags != nil {
|
||||
if !restrictedTagsEqual(tags, nil, globals.immutableTagNS) {
|
||||
logs.Warn.Println("create user: attempt to directly assign restricted tags, sid=", s.sid)
|
||||
msg := ErrPermissionDenied(msg.Id, "", msg.Timestamp)
|
||||
msg.Ctrl.Params = map[string]any{"what": "tags"}
|
||||
s.queueOut(msg)
|
||||
return
|
||||
}
|
||||
user.Tags = tags
|
||||
if msg.Acc.Tags != nil {
|
||||
logs.Warn.Println("create user: user tags are no longer supported, sid=", s.sid)
|
||||
msg := ErrPermissionDenied(msg.Id, "", msg.Timestamp)
|
||||
msg.Ctrl.Params = map[string]any{"what": "tags"}
|
||||
s.queueOut(msg)
|
||||
return
|
||||
}
|
||||
|
||||
// Pre-check credentials for validity. We don't know user's access level
|
||||
// consequently cannot check presence of required credentials. Must do that later.
|
||||
creds := normalizeCredentials(msg.Acc.Cred, true)
|
||||
var registrationPhone string
|
||||
for i := range creds {
|
||||
cr := &creds[i]
|
||||
vld := store.Store.GetValidator(cr.Method)
|
||||
if _, err := vld.PreCheck(cr.Value, cr.Params); err != nil {
|
||||
normalized, err := vld.PreCheck(cr.Value, cr.Params)
|
||||
if err != nil {
|
||||
logs.Warn.Println("create user: failed credential pre-check", cr, err, "sid=", s.sid)
|
||||
s.queueOut(decodeStoreError(err, msg.Id, msg.Timestamp,
|
||||
map[string]any{"what": cr.Method}))
|
||||
return
|
||||
}
|
||||
if cr.Method == "tel" {
|
||||
phone := strings.TrimSpace(strings.TrimPrefix(normalized, "tel:"))
|
||||
challengeID, _ := cr.Params["challenge_id"].(string)
|
||||
if phone == "" || strings.TrimSpace(challengeID) == "" || strings.TrimSpace(cr.Response) == "" ||
|
||||
(registrationPhone != "" && registrationPhone != phone) {
|
||||
s.queueOut(decodeStoreError(types.ErrCredentials, msg.Id, msg.Timestamp,
|
||||
map[string]any{"creds": []string{"tel"}}))
|
||||
return
|
||||
}
|
||||
registrationPhone = phone
|
||||
}
|
||||
}
|
||||
if registrationPhone == "" && store.Verifications != nil {
|
||||
logs.Warn.Println("create user: verified phone is required, sid=", s.sid)
|
||||
s.queueOut(decodeStoreError(types.ErrCredentials, msg.Id, msg.Timestamp,
|
||||
map[string]any{"creds": []string{"tel"}}))
|
||||
return
|
||||
}
|
||||
user.Phone = registrationPhone
|
||||
|
||||
// Assign default access values in case the acc creator has not provided them
|
||||
user.Access.Auth = getDefaultAccess(types.TopicCatP2P, true, false) |
|
||||
@@ -138,9 +154,9 @@ func replyCreateUser(s *Session, msg *ClientComMessage, rec *auth.Rec) {
|
||||
return
|
||||
}
|
||||
|
||||
// Add authentication record. The authhdl.AddRecord may change tags.
|
||||
// Add authentication record.
|
||||
rec, err := authhdl.AddRecord(authCtx,
|
||||
&auth.Rec{TenantID: s.tenantID, Uid: user.Uid(), Tags: user.Tags}, msg.Acc.Secret)
|
||||
&auth.Rec{TenantID: s.tenantID, Uid: user.Uid()}, msg.Acc.Secret)
|
||||
if err != nil {
|
||||
logs.Warn.Println("create user: add auth record failed", err, "sid=", s.sid)
|
||||
s.queueOut(decodeStoreError(err, msg.Id, msg.Timestamp, nil))
|
||||
@@ -167,14 +183,14 @@ func replyCreateUser(s *Session, msg *ClientComMessage, rec *auth.Rec) {
|
||||
return
|
||||
}
|
||||
|
||||
// Save credentials, update tags if necessary.
|
||||
// Save and validate credentials.
|
||||
tmpToken, _, _ := store.Store.GetLogicalAuthHandler("token").GenSecret(&auth.Rec{
|
||||
TenantID: s.tenantID,
|
||||
Uid: user.Uid(),
|
||||
AuthLevel: auth.LevelAuth,
|
||||
Lifetime: auth.Duration(time.Hour * 24),
|
||||
})
|
||||
validated, _, err := addCreds(s.tenantID, user.Uid(), creds, rec.Tags, s.lang, tmpToken)
|
||||
validated, _, err := addCreds(s.tenantID, user.Uid(), creds, nil, s.lang, tmpToken)
|
||||
if err != nil {
|
||||
logs.Warn.Println("create user: failed to save or validate credential", err, "sid=", s.sid)
|
||||
s.queueOut(decodeStoreError(err, msg.Id, msg.Timestamp, nil))
|
||||
@@ -351,17 +367,11 @@ func updateUserAuth(tenantID types.TenantID, msg *ClientComMessage, user *types.
|
||||
|
||||
// TODO(gene): support adding new auth schemes
|
||||
|
||||
rec, err := authhdl.UpdateRecord(auth.AuthContext{TenantID: tenantID, RemoteAddr: remoteAddr},
|
||||
&auth.Rec{TenantID: tenantID, Uid: user.Uid(), Tags: user.Tags}, msg.Acc.Secret)
|
||||
_, err := authhdl.UpdateRecord(auth.AuthContext{TenantID: tenantID, RemoteAddr: remoteAddr},
|
||||
&auth.Rec{TenantID: tenantID, Uid: user.Uid()}, msg.Acc.Secret)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Tags may have been changed by authhdl.UpdateRecord, reset them.
|
||||
// Can't do much with the error here, logging it but not returning.
|
||||
if _, err = store.Users.UpdateTags(tenantID, user.Uid(), nil, nil, rec.Tags); err != nil {
|
||||
logs.Warn.Println("updateUserAuth tags update failed:", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -369,11 +379,8 @@ func updateUserAuth(tenantID types.TenantID, msg *ClientComMessage, user *types.
|
||||
return types.ErrMalformed
|
||||
}
|
||||
|
||||
// addCreds adds new credentials and re-send validation request for existing ones.
|
||||
// It also adds credential-defined tags if necessary.
|
||||
// Returns methods validated in this call only. Returns either a full set of tags
|
||||
// or nil for tags when tags are unchanged.
|
||||
func addCreds(tenantID types.TenantID, uid types.Uid, creds []MsgCredClient, extraTags []string,
|
||||
// addCreds adds credentials and re-sends validation requests for existing ones.
|
||||
func addCreds(tenantID types.TenantID, uid types.Uid, creds []MsgCredClient, _ []string,
|
||||
lang string, tmpToken []byte) ([]string, []string, error) {
|
||||
var validated []string
|
||||
for i := range creds {
|
||||
@@ -385,14 +392,11 @@ func addCreds(tenantID types.TenantID, uid types.Uid, creds []MsgCredClient, ext
|
||||
}
|
||||
|
||||
if cr.Response != "" {
|
||||
if value, ok, err := consumeProductVerificationCred(tenantID, uid, cr, vld.PreCheck); ok || err != nil {
|
||||
if _, ok, err := consumeProductVerificationCred(tenantID, uid, cr, vld.PreCheck); ok || err != nil {
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
validated = append(validated, cr.Method)
|
||||
if globals.validators[cr.Method].addToTags {
|
||||
extraTags = append(extraTags, cr.Method+":"+value)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -407,24 +411,9 @@ func addCreds(tenantID types.TenantID, uid types.Uid, creds []MsgCredClient, ext
|
||||
// successfully validated.
|
||||
validated = append(validated, cr.Method)
|
||||
|
||||
// Generate tags for these confirmed credentials.
|
||||
if globals.validators[cr.Method].addToTags {
|
||||
extraTags = append(extraTags, cr.Method+":"+cr.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save tags potentially changed by the validator.
|
||||
if len(extraTags) > 0 {
|
||||
if utags, err := store.Users.UpdateTags(tenantID, uid, extraTags, nil, nil); err == nil {
|
||||
extraTags = utags
|
||||
} else {
|
||||
logs.Warn.Println("add cred tags update failed:", err)
|
||||
}
|
||||
} else {
|
||||
extraTags = nil
|
||||
}
|
||||
return validated, extraTags, nil
|
||||
return validated, nil, nil
|
||||
}
|
||||
|
||||
func consumeProductVerificationCred(tenantID types.TenantID, uid types.Uid, cr *MsgCredClient,
|
||||
@@ -475,7 +464,6 @@ func consumeProductVerificationCred(tenantID types.TenantID, uid types.Uid, cr *
|
||||
|
||||
// validatedCreds returns the list of validated credentials including those validated in this call.
|
||||
// Returns all validated methods including those validated earlier and now.
|
||||
// Returns either a full set of tags or nil for tags if tags are unchanged.
|
||||
func validatedCreds(tenantID types.TenantID, uid types.Uid, authLvl auth.Level, creds []MsgCredClient,
|
||||
errorOnFail bool) ([]string, []string, error) {
|
||||
// Check if credential validation is required.
|
||||
@@ -497,7 +485,6 @@ func validatedCreds(tenantID types.TenantID, uid types.Uid, authLvl auth.Level,
|
||||
// Add credentials which are validated in this call.
|
||||
// Unknown validators are removed.
|
||||
creds = normalizeCredentials(creds, false)
|
||||
var tagsToAdd []string
|
||||
for i := range creds {
|
||||
cr := &creds[i]
|
||||
if cr.Response == "" {
|
||||
@@ -506,7 +493,7 @@ func validatedCreds(tenantID types.TenantID, uid types.Uid, authLvl auth.Level,
|
||||
}
|
||||
|
||||
vld := store.Store.GetValidator(cr.Method) // No need to check for nil, unknown methods are removed earlier.
|
||||
value, err := vld.Check(tenantID, uid, cr.Response)
|
||||
_, err := vld.Check(tenantID, uid, cr.Response)
|
||||
|
||||
if err != nil {
|
||||
// Check failed.
|
||||
@@ -525,23 +512,6 @@ func validatedCreds(tenantID types.TenantID, uid types.Uid, authLvl auth.Level,
|
||||
// Check did not return an error: the request was successfully validated.
|
||||
methods[cr.Method] = struct{}{}
|
||||
|
||||
// Add validated credential to user's tags.
|
||||
if globals.validators[cr.Method].addToTags {
|
||||
tagsToAdd = append(tagsToAdd, cr.Method+":"+value)
|
||||
}
|
||||
}
|
||||
|
||||
var tags []string
|
||||
if len(tagsToAdd) > 0 {
|
||||
// Save update to tags
|
||||
if utags, err := store.Users.UpdateTags(tenantID, uid, tagsToAdd, nil, nil); err == nil {
|
||||
tags = utags
|
||||
} else {
|
||||
logs.Warn.Println("validated creds tags update failed:", err)
|
||||
tags = nil
|
||||
}
|
||||
} else {
|
||||
tags = nil
|
||||
}
|
||||
|
||||
validated := make([]string, 0, len(methods))
|
||||
@@ -549,11 +519,10 @@ func validatedCreds(tenantID types.TenantID, uid types.Uid, authLvl auth.Level,
|
||||
validated = append(validated, method)
|
||||
}
|
||||
|
||||
return validated, tags, nil
|
||||
return validated, nil, nil
|
||||
}
|
||||
|
||||
// deleteCred deletes user's credential.
|
||||
// Returns full set of remaining tags or nil if tags are unchanged.
|
||||
func deleteCred(tenantID types.TenantID, uid types.Uid, authLvl auth.Level, cred *MsgCredClient) ([]string, error) {
|
||||
vld := store.Store.GetValidator(cred.Method)
|
||||
if vld == nil || cred.Value == "" {
|
||||
@@ -601,21 +570,7 @@ func deleteCred(tenantID types.TenantID, uid types.Uid, authLvl auth.Level, cred
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Remove generated tags for the deleted credential.
|
||||
var tags []string
|
||||
if globals.validators[cred.Method].addToTags {
|
||||
// This error should not be returned to user.
|
||||
if utags, err := store.Users.UpdateTags(tenantID, uid, nil, []string{cred.Method + ":" + cred.Value}, nil); err == nil {
|
||||
tags = utags
|
||||
} else {
|
||||
logs.Warn.Println("delete cred: failed to update tags:", err)
|
||||
tags = nil
|
||||
}
|
||||
} else {
|
||||
tags = nil
|
||||
}
|
||||
|
||||
return tags, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Change user state: suspended/normal (ok).
|
||||
|
||||
Reference in New Issue
Block a user