fix: restore verification target user ids
This commit is contained in:
@@ -1546,6 +1546,32 @@ func createIMRelationTables(exec sqlExecutor) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createIMSecurityTables(tx *sql.Tx) error {
|
func createIMSecurityTables(tx *sql.Tx) error {
|
||||||
|
if _, err := tx.Exec(
|
||||||
|
`CREATE TABLE im_verification_codes(
|
||||||
|
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
challenge_id VARCHAR(64) NOT NULL,
|
||||||
|
scene VARCHAR(32) NOT NULL,
|
||||||
|
action VARCHAR(64) NOT NULL DEFAULT '',
|
||||||
|
phone_hash CHAR(64) NOT NULL,
|
||||||
|
phone_mask VARCHAR(32) NOT NULL,
|
||||||
|
target_user BIGINT,
|
||||||
|
code_hash CHAR(64) NOT NULL,
|
||||||
|
verification_token_hash CHAR(64),
|
||||||
|
state SMALLINT NOT NULL,
|
||||||
|
attempts INT NOT NULL DEFAULT 0,
|
||||||
|
max_attempts INT NOT NULL,
|
||||||
|
expires_at DATETIME(3) NOT NULL,
|
||||||
|
resend_after DATETIME(3) NOT NULL,
|
||||||
|
verified_at DATETIME(3),
|
||||||
|
consumed_at DATETIME(3),
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||||
|
PRIMARY KEY(id),
|
||||||
|
UNIQUE INDEX uk_im_verification_challenge(challenge_id),
|
||||||
|
INDEX idx_im_verification_scene_phone_state(scene, phone_hash, state, expires_at)
|
||||||
|
)`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if _, err := tx.Exec(
|
if _, err := tx.Exec(
|
||||||
`CREATE TABLE im_realname_verifications(
|
`CREATE TABLE im_realname_verifications(
|
||||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
|||||||
@@ -5466,8 +5466,8 @@ func (a *adapter) TenantVerificationGet(id t.TenantID, challengeID string) (*t.V
|
|||||||
if cancel != nil {
|
if cancel != nil {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
}
|
}
|
||||||
var vc t.VerificationCode
|
var row verificationCodeRow
|
||||||
err := a.db.GetContext(ctx, &vc,
|
err := a.db.GetContext(ctx, &row,
|
||||||
`SELECT id,challenge_id,scene,action,phone_hash,phone_mask,IFNULL(target_user,0) AS target_user,code_hash,verification_token_hash,
|
`SELECT id,challenge_id,scene,action,phone_hash,phone_mask,IFNULL(target_user,0) AS target_user,code_hash,verification_token_hash,
|
||||||
state,attempts,max_attempts,expires_at,resend_after,verified_at,consumed_at,created_at,updated_at
|
state,attempts,max_attempts,expires_at,resend_after,verified_at,consumed_at,created_at,updated_at
|
||||||
FROM im_verification_codes
|
FROM im_verification_codes
|
||||||
@@ -5478,8 +5478,7 @@ func (a *adapter) TenantVerificationGet(id t.TenantID, challengeID string) (*t.V
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
vc.TenantID = id
|
return row.toVerificationCode(id), nil
|
||||||
return &vc, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *adapter) TenantVerificationGetActive(id t.TenantID, scene, phoneHash string, now time.Time) (*t.VerificationCode, error) {
|
func (a *adapter) TenantVerificationGetActive(id t.TenantID, scene, phoneHash string, now time.Time) (*t.VerificationCode, error) {
|
||||||
@@ -5499,8 +5498,8 @@ func (a *adapter) TenantVerificationGetActive(id t.TenantID, scene, phoneHash st
|
|||||||
if cancel != nil {
|
if cancel != nil {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
}
|
}
|
||||||
var vc t.VerificationCode
|
var row verificationCodeRow
|
||||||
err := a.db.GetContext(ctx, &vc,
|
err := a.db.GetContext(ctx, &row,
|
||||||
`SELECT id,challenge_id,scene,action,phone_hash,phone_mask,IFNULL(target_user,0) AS target_user,code_hash,verification_token_hash,
|
`SELECT id,challenge_id,scene,action,phone_hash,phone_mask,IFNULL(target_user,0) AS target_user,code_hash,verification_token_hash,
|
||||||
state,attempts,max_attempts,expires_at,resend_after,verified_at,consumed_at,created_at,updated_at
|
state,attempts,max_attempts,expires_at,resend_after,verified_at,consumed_at,created_at,updated_at
|
||||||
FROM im_verification_codes
|
FROM im_verification_codes
|
||||||
@@ -5512,8 +5511,55 @@ func (a *adapter) TenantVerificationGetActive(id t.TenantID, scene, phoneHash st
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
vc.TenantID = id
|
return row.toVerificationCode(id), nil
|
||||||
return &vc, nil
|
}
|
||||||
|
|
||||||
|
type verificationCodeRow struct {
|
||||||
|
ID int64 `db:"id"`
|
||||||
|
ChallengeID string `db:"challenge_id"`
|
||||||
|
Scene string `db:"scene"`
|
||||||
|
Action string `db:"action"`
|
||||||
|
PhoneHash string `db:"phone_hash"`
|
||||||
|
PhoneMask string `db:"phone_mask"`
|
||||||
|
TargetUser int64 `db:"target_user"`
|
||||||
|
CodeHash string `db:"code_hash"`
|
||||||
|
VerificationTokenHash *string `db:"verification_token_hash"`
|
||||||
|
State t.VerificationState `db:"state"`
|
||||||
|
Attempts int `db:"attempts"`
|
||||||
|
MaxAttempts int `db:"max_attempts"`
|
||||||
|
ExpiresAt time.Time `db:"expires_at"`
|
||||||
|
ResendAfter time.Time `db:"resend_after"`
|
||||||
|
VerifiedAt *time.Time `db:"verified_at"`
|
||||||
|
ConsumedAt *time.Time `db:"consumed_at"`
|
||||||
|
CreatedAt time.Time `db:"created_at"`
|
||||||
|
UpdatedAt time.Time `db:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r verificationCodeRow) toVerificationCode(tenantID t.TenantID) *t.VerificationCode {
|
||||||
|
vc := &t.VerificationCode{
|
||||||
|
ID: r.ID,
|
||||||
|
TenantID: tenantID,
|
||||||
|
ChallengeID: r.ChallengeID,
|
||||||
|
Scene: r.Scene,
|
||||||
|
Action: r.Action,
|
||||||
|
PhoneHash: r.PhoneHash,
|
||||||
|
PhoneMask: r.PhoneMask,
|
||||||
|
CodeHash: r.CodeHash,
|
||||||
|
VerificationTokenHash: r.VerificationTokenHash,
|
||||||
|
State: r.State,
|
||||||
|
Attempts: r.Attempts,
|
||||||
|
MaxAttempts: r.MaxAttempts,
|
||||||
|
ExpiresAt: r.ExpiresAt,
|
||||||
|
ResendAfter: r.ResendAfter,
|
||||||
|
VerifiedAt: r.VerifiedAt,
|
||||||
|
ConsumedAt: r.ConsumedAt,
|
||||||
|
CreatedAt: r.CreatedAt,
|
||||||
|
UpdatedAt: r.UpdatedAt,
|
||||||
|
}
|
||||||
|
if r.TargetUser > 0 {
|
||||||
|
vc.TargetUser = store.EncodeUid(r.TargetUser)
|
||||||
|
}
|
||||||
|
return vc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *adapter) TenantVerificationFail(id t.TenantID, challengeID string, state t.VerificationState) error {
|
func (a *adapter) TenantVerificationFail(id t.TenantID, challengeID string, state t.VerificationState) error {
|
||||||
|
|||||||
@@ -472,6 +472,55 @@ func TestRegistrationInviteReusableSchema(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVerificationTargetUserRoundTrip(t *testing.T) {
|
||||||
|
tenantAdapter, ok := adp.(adapter.TenantBusinessAdapter)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("MySQL adapter does not implement TenantBusinessAdapter")
|
||||||
|
}
|
||||||
|
var tenantID types.TenantID
|
||||||
|
if err := db.Get(&tenantID, "SELECT id FROM im_tenant WHERE code='default'"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
uid := types.ParseUserId("usr" + testData.Users[0].Id)
|
||||||
|
now := types.TimeNow()
|
||||||
|
challengeID := "challenge-roundtrip-target-user"
|
||||||
|
phoneHash := "verification-target-user-phone-hash"
|
||||||
|
_, _ = db.Exec("DELETE FROM im_verification_codes WHERE challenge_id=? OR phone_hash=?", challengeID, phoneHash)
|
||||||
|
vc := &types.VerificationCode{
|
||||||
|
TenantID: tenantID,
|
||||||
|
ChallengeID: challengeID,
|
||||||
|
Scene: "reset_password",
|
||||||
|
PhoneHash: phoneHash,
|
||||||
|
PhoneMask: "+86******0000",
|
||||||
|
TargetUser: uid,
|
||||||
|
CodeHash: strings.Repeat("a", 64),
|
||||||
|
State: types.VerificationStatePending,
|
||||||
|
MaxAttempts: 5,
|
||||||
|
ExpiresAt: now.Add(time.Hour),
|
||||||
|
ResendAfter: now.Add(time.Minute),
|
||||||
|
}
|
||||||
|
if err := tenantAdapter.TenantVerificationCreate(tenantID, vc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stored, err := tenantAdapter.TenantVerificationGet(tenantID, challengeID)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if stored.TargetUser != uid {
|
||||||
|
t.Fatalf("Get target user: got %s, want %s", stored.TargetUser.UserId(), uid.UserId())
|
||||||
|
}
|
||||||
|
|
||||||
|
active, err := tenantAdapter.TenantVerificationGetActive(tenantID, "reset_password", phoneHash, now)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if active.TargetUser != uid {
|
||||||
|
t.Fatalf("GetActive target user: got %s, want %s", active.TargetUser.UserId(), uid.UserId())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTopicCreate(t *testing.T) {
|
func TestTopicCreate(t *testing.T) {
|
||||||
err := adp.TopicCreate(testData.Topics[0])
|
err := adp.TopicCreate(testData.Topics[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user