feat: sync iOS compatibility support

This commit is contained in:
A 2026-07-13 00:58:57 +08:00
parent 1f646ef024
commit 50803a604c
32 changed files with 871 additions and 78 deletions

View file

@ -183,6 +183,25 @@ UPDATE authorizations SET layer = $2, active_at = now() WHERE auth_key_id = $1`,
return nil
}
func (s *AuthorizationStore) UpdateClientInfo(ctx context.Context, id [8]byte, info domain.AuthKeyClientInfo) error {
if _, err := s.db.Exec(ctx, `
UPDATE authorizations SET
layer = CASE WHEN $2 > 0 THEN $2 ELSE layer END,
device_model = CASE WHEN $3 <> '' THEN $3 ELSE device_model END,
platform = CASE WHEN $4 <> '' THEN $4 ELSE platform END,
system_version = CASE WHEN $5 <> '' THEN $5 ELSE system_version END,
api_id = CASE WHEN $6 <> 0 THEN $6 ELSE api_id END,
app_version = CASE WHEN $7 <> '' THEN $7 ELSE app_version END,
active_at = now()
WHERE auth_key_id = $1`,
authKeyIDToInt64(id), int32(info.Layer), info.DeviceModel, info.Platform,
info.SystemVersion, int32(info.APIID), info.AppVersion,
); err != nil {
return fmt.Errorf("update authorization client info: %w", err)
}
return nil
}
// MarkPasswordPassed 在两步验证通过后清除 password_pending,使 auth_key 转为完全授权。
func (s *AuthorizationStore) MarkPasswordPassed(ctx context.Context, id [8]byte) error {
if _, err := s.db.Exec(ctx, `

View file

@ -110,6 +110,49 @@ func TestAuthorizationStoreRevokeByUserExceptDeletesOnlyRevokedKeysPostgres(t *t
assertRevokeTestMissingAuthKey(t, ctx, keys, tempForTwo)
}
func TestAuthorizationStoreUpdateClientInfoMergesPostgres(t *testing.T) {
pool := testPool(t)
ctx := context.Background()
userID := createRevokeTestUser(t, ctx, pool, "client-info")
id := revokeTestAuthKeyID(0xb1)
keys := NewAuthKeyStore(pool)
auths := NewAuthorizationStore(pool)
saveRevokeTestAuthKey(t, ctx, keys, id)
if err := auths.Bind(ctx, domain.Authorization{
AuthKeyID: id,
UserID: userID,
Hash: 9201,
Platform: "unknown",
DeviceModel: "legacy",
IP: "127.0.0.1",
}); err != nil {
t.Fatalf("bind authorization: %v", err)
}
if err := auths.UpdateClientInfo(ctx, id, domain.AuthKeyClientInfo{
Layer: 227,
DeviceModel: "iPhone Simulator",
Platform: "ios",
SystemVersion: "26.5",
APIID: 1,
AppVersion: "12.8 (10000)",
}); err != nil {
t.Fatalf("update client info: %v", err)
}
// Empty/zero values are a partial update and must not erase strong metadata.
if err := auths.UpdateClientInfo(ctx, id, domain.AuthKeyClientInfo{AppVersion: "12.8.1"}); err != nil {
t.Fatalf("partial update client info: %v", err)
}
got, found, err := auths.ByAuthKey(ctx, id)
if err != nil || !found {
t.Fatalf("get authorization: found=%v err=%v", found, err)
}
if got.Layer != 227 || got.DeviceModel != "iPhone Simulator" || got.Platform != "ios" ||
got.SystemVersion != "26.5" || got.APIID != 1 || got.AppVersion != "12.8.1" {
t.Fatalf("merged client info = %+v", got)
}
}
func createRevokeTestUser(t *testing.T, ctx context.Context, db *pgxpool.Pool, suffix string) int64 {
t.Helper()
phone := fmt.Sprintf("+1555%09d", time.Now().UnixNano()%1_000_000_000)