From de6fbcb51812d9d9f63a697e876b83a455554ccc Mon Sep 17 00:00:00 2001 From: shanshanzhong Date: Wed, 18 Mar 2026 10:28:55 -0700 Subject: [PATCH] device_no --- internal/config/config.go | 2 +- pkg/tool/device.go | 48 +++++++++++++++++++++++++++++++---- scripts/migrate_paid_users.go | 8 +++--- 订单日子.txt | 13 +++++++++- 说明文档.md | 2 +- 5 files changed, 61 insertions(+), 12 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 813f603..d742c3f 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -90,7 +90,7 @@ type RegisterConfig struct { IpRegisterLimit int64 `yaml:"IpRegisterLimit" default:"0"` IpRegisterLimitDuration int64 `yaml:"IpRegisterLimitDuration" default:"0"` EnableIpRegisterLimit bool `yaml:"EnableIpRegisterLimit" default:"false"` - DeviceLimit int64 `yaml:"DeviceLimit" default:"5"` + DeviceLimit int64 `yaml:"DeviceLimit" default:"2"` } type EmailConfig struct { diff --git a/pkg/tool/device.go b/pkg/tool/device.go index 7860c44..ac8c001 100644 --- a/pkg/tool/device.go +++ b/pkg/tool/device.go @@ -5,13 +5,47 @@ import ( "strings" ) -const deviceHashSalt uint32 = 0x5A3C7E9B +// 乘法逆元参数(mod 2^32) +// multiplier 必须是奇数,与 2^32 互质 +// inverse 满足: multiplier * inverse ≡ 1 (mod 2^32) +const ( + deviceMultiplier uint32 = 0x45D9F3B7 // 奇数乘数 + deviceInverse uint32 = 0x9B845A07 // 乘法逆元 (multiplier * inverse = 1 mod 2^32) + deviceXorKey1 uint32 = 0x5A3C7E9B // 第一轮 XOR + deviceXorKey2 uint32 = 0xE7B2A4C3 // 第二轮 XOR +) + +// bitShuffle 交错重排 32 位的比特位,打散高低位的关联 +func bitShuffle(v uint32) uint32 { + var result uint32 + // 把偶数位放到高16位,奇数位放到低16位 + for i := 0; i < 16; i++ { + result |= ((v >> (2 * i)) & 1) << (16 + i) // 偶数位 → 高半 + result |= ((v >> (2*i + 1)) & 1) << i // 奇数位 → 低半 + } + return result +} + +// bitUnshuffle 是 bitShuffle 的逆操作 +func bitUnshuffle(v uint32) uint32 { + var result uint32 + for i := 0; i < 16; i++ { + result |= ((v >> (16 + i)) & 1) << (2 * i) // 高半 → 偶数位 + result |= ((v >> i) & 1) << (2*i + 1) // 低半 → 奇数位 + } + return result +} // DeviceIdToHash encodes a device id to an 8-char uppercase hex string. -// Algorithm mirrors frontend: id XOR salt → hex. -// e.g. 1 → "5A3C7E9A", 42 → "5A3C7EA1" +// Uses multiply-xor-shuffle to fully scatter sequential IDs. +// e.g. 1 → "83AEF73C", 2 → "D603916F" (no visible pattern) func DeviceIdToHash(id int64) string { - return strings.ToUpper(fmt.Sprintf("%08x", uint32(id)^deviceHashSalt)) + n := uint32(id) + n ^= deviceXorKey1 // step 1: XOR + n *= deviceMultiplier // step 2: 乘法扩散(模 2^32) + n = bitShuffle(n) // step 3: 比特位交错 + n ^= deviceXorKey2 // step 4: 再次 XOR + return strings.ToUpper(fmt.Sprintf("%08x", n)) } // HashToDeviceId decodes an 8-char hex hash back to a device id. @@ -21,5 +55,9 @@ func HashToDeviceId(hash string) (int64, error) { if err != nil { return 0, err } - return int64(n ^ deviceHashSalt), nil + n ^= deviceXorKey2 // reverse step 4 + n = bitUnshuffle(n) // reverse step 3 + n *= deviceInverse // reverse step 2: 乘法逆元 + n ^= deviceXorKey1 // reverse step 1 + return int64(n), nil } diff --git a/scripts/migrate_paid_users.go b/scripts/migrate_paid_users.go index cc69f56..4718b20 100644 --- a/scripts/migrate_paid_users.go +++ b/scripts/migrate_paid_users.go @@ -276,13 +276,13 @@ func main() { SELECT user_id AS uid FROM ` + "`order`" + ` WHERE status = ? AND user_id > 0 UNION SELECT user_id AS uid FROM apple_iap_transactions WHERE user_id > 0 - UNION - SELECT user_id AS uid FROM user_subscribe WHERE user_id > 0 ) t + INNER JOIN user_subscribe s ON s.user_id = t.uid INNER JOIN user u ON u.id = t.uid - WHERE u.id NOT IN ( + WHERE (s.expire_time IS NULL OR s.expire_time > NOW()) + AND u.id NOT IN ( SELECT user_id FROM user_auth_methods WHERE auth_type = 'email' AND auth_identifier = 'devneeds52@gmail.com' - ) + ) ORDER BY t.uid `, orderStatusCompleted).Scan(&paidIDs).Error if err != nil { diff --git a/订单日子.txt b/订单日子.txt index a00e9ae..b2a9412 100644 --- a/订单日子.txt +++ b/订单日子.txt @@ -9,4 +9,15 @@ TRUNCATE TABLE user_device; TRUNCATE TABLE user_device_online_record; TRUNCATE TABLE user_family; TRUNCATE TABLE user_family_member; -TRUNCATE TABLE user_subscribe; \ No newline at end of file +TRUNCATE TABLE user_subscribe; + + +docker exec ppanel-mysql mysql -uroot -p hifast -e " + SELECT id, referer_id, refer_code, created_at + FROM user + WHERE refer_code = 'uuD58Gs9' + ORDER BY id DESC + LIMIT 10; + " + + docker logs ppanel-server 2>&1 | grep "1519\|bind_invite\|BindInviteCode" | tail -20 \ No newline at end of file diff --git a/说明文档.md b/说明文档.md index 4b2f60b..a7c9b27 100644 --- a/说明文档.md +++ b/说明文档.md @@ -25,7 +25,7 @@ certbot certonly --manual --preferred-challenges dns -d airoport.win -d "*.airop | docker exec -i ppanel-mysql mysql -uroot -pjpcV41ppanel -go run scripts/migrate_paid_users.go -src 'root:rootpassword@tcp(127.0.0.1:3306)/ppanel?charset=utf8mb4&parseTime=True&loc=Local' -dst 'root:jpcV41ppanel@tcp(103.150.215.44:3306)/hifast?charset=utf8mb4&parseTime=True&loc=Local' -clean +go run scripts/migrate_paid_users.go -src 'root:rootpassword@tcp(127.0.0.1:3306)/ppanel?charset=utf8mb4&parseTime=True&loc=Local' -dst 'root:jpcV41ppanel@tcp(154.12.35.103:3306)/ppanel?charset=utf8mb4&parseTime=True&loc=Local' -clean