From dbf8b5bcca9d2fc6a14fe0a9917fef2b1a8acfe3 Mon Sep 17 00:00:00 2001 From: zyj <18107291228@163.com> Date: Tue, 30 Sep 2025 11:19:39 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BF=AE=E6=94=B9=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/twitter.go | 22 +++ go.mod | 9 +- go.sum | 14 +- libs/chrome.go | 23 +++- plugin/task-account-unlock-plugin.go | 2 +- router/twitter.go | 1 + services/bit_browser_service.go | 148 ++++++++++++++++---- services/twitter_service.go | 196 ++++++++++++++++++++++++++- utils/index.go | 18 +++ 9 files changed, 391 insertions(+), 42 deletions(-) diff --git a/api/twitter.go b/api/twitter.go index 33f78a3..976e7ca 100644 --- a/api/twitter.go +++ b/api/twitter.go @@ -68,3 +68,25 @@ func (*Twitter) Register(ctx *gin.Context) { "data": res.Data, }) } + +func (*Twitter) Register1(ctx *gin.Context) { + var res *libs.ErrorInfo + var paramsJson RegisterParams + if err := ctx.ShouldBindJSON(¶msJson); err != nil { + res = libs.ErrorCode["ParamsError"] + fmt.Println(err) + ctx.JSON(http.StatusBadRequest, gin.H{ + "code": res.Code, + "msg": res.Msg, + "data": res.Data, + }) + return + } + var TwitterService services.TwitterService + res = TwitterService.Register() + ctx.JSON(http.StatusOK, gin.H{ + "code": res.Code, + "msg": res.Msg, + "data": res.Data, + }) +} diff --git a/go.mod b/go.mod index bce97c2..77eb435 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,9 @@ module go-account-register go 1.24.3 require ( + github.com/PuerkitoBio/goquery v1.10.3 + github.com/emersion/go-imap v1.2.1 + github.com/emersion/go-message v0.18.2 github.com/fatih/structs v1.1.0 github.com/gin-gonic/gin v1.10.1 github.com/go-resty/resty/v2 v2.16.5 @@ -10,6 +13,7 @@ require ( github.com/go-rod/stealth v0.4.9 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 github.com/google/uuid v1.6.0 + github.com/pquerna/otp v1.5.0 github.com/redis/go-redis/v9 v9.14.0 golang.org/x/image v0.31.0 gopkg.in/yaml.v3 v3.0.1 @@ -19,16 +23,15 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect - github.com/PuerkitoBio/goquery v1.10.3 // indirect github.com/andybalholm/cascadia v1.3.3 // indirect + github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect + github.com/corpix/uarand v0.2.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/emersion/go-imap v1.2.1 // indirect - github.com/emersion/go-message v0.18.2 // indirect github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect diff --git a/go.sum b/go.sum index e0396b2..262dd92 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiU github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y= github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM= github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= @@ -18,6 +20,8 @@ github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/ github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/corpix/uarand v0.2.0 h1:U98xXwud/AVuCpkpgfPF7J5TQgr7R5tqT8VZP5KWbzE= +github.com/corpix/uarand v0.2.0/go.mod h1:/3Z1QIqWkDIhf6XWn/08/uMHoQ8JUoTIKc2iPchBOmM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -60,8 +64,7 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -89,6 +92,8 @@ github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6 github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs= +github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/redis/go-redis/v9 v9.14.0 h1:u4tNCjXOyzfgeLN+vAZaW1xUooqWDqVEsZN0U01jfAE= github.com/redis/go-redis/v9 v9.14.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -133,7 +138,6 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= @@ -152,7 +156,6 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= @@ -174,7 +177,6 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= @@ -208,8 +210,6 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/libs/chrome.go b/libs/chrome.go index 11e2e0b..1195ccb 100644 --- a/libs/chrome.go +++ b/libs/chrome.go @@ -3,6 +3,7 @@ package libs import ( browserfingerprint "go-account-register/libs/browser-fingerprint" paramsTypes "go-account-register/types" + "go-account-register/utils" "go-account-register/utils/external" "log" "os" @@ -10,7 +11,9 @@ import ( "strconv" "strings" + "github.com/corpix/uarand" "github.com/go-rod/rod" + "github.com/go-rod/rod/lib/devices" "github.com/go-rod/rod/lib/launcher" "github.com/go-rod/rod/lib/proto" "github.com/go-rod/stealth" @@ -139,6 +142,8 @@ func (c *Chrome) Create(accountId int, params *Fingerprint) (*rod.Browser, strin } func (c *Chrome) TemporaryCreate(params *Fingerprint) (*rod.Browser, string, *rod.Page) { + userDataDir := "user-data/" + utils.RandString(5) + absPath, _ := filepath.Abs(userDataDir) path, _ := launcher.LookPath() // 获取当前系统的浏览器目录 // 判断是否传递代理 // var proxyHandle utils.ProxyHandle @@ -152,6 +157,7 @@ func (c *Chrome) TemporaryCreate(params *Fingerprint) (*rod.Browser, string, *ro Delete("use-mock-keychain"). // delete flag "--use-mock-keychain" Set("disable-blink-features", "AutomationControlled"). // 绕过自动化检测 // Set("incognito"). // 无痕模式 + Set("user-data-dir", absPath). // 数据持久化目录 Set("window-size", "1920,1480"). // 窗口尺寸 Set("disable-infobars", "true"). // 隐藏自动化提示栏 Set("no-sandbox", "true"). @@ -186,6 +192,20 @@ func (c *Chrome) TemporaryCreate(params *Fingerprint) (*rod.Browser, string, *ro Set("timezone", ipInfo.Timezone). Set("geolocation", ipInfo.Lat+","+ipInfo.Lon) + ua := uarand.GetRandom() + screen := devices.Device{ + Title: "Laptop with MDPI screen", + Capabilities: []string{"touch", "mobile"}, + UserAgent: ua, + AcceptLanguage: "en-US,en;q=0.9", + Screen: devices.Screen{ + DevicePixelRatio: 1, + Horizontal: devices.ScreenSize{ + Width: 1920, + Height: 1480, + }, + }, + } // if errProxy == nil { // if strings.Contains(protocol, "http") { // log.Println(protocol + "://" + ip + ":" + port) @@ -197,8 +217,9 @@ func (c *Chrome) TemporaryCreate(params *Fingerprint) (*rod.Browser, string, *ro browser := rod.New(). ControlURL(uri). - MustConnect().NoDefaultDevice() + MustConnect().DefaultDevice(screen) browser.MustIgnoreCertErrors(true) + // if errProxy == nil { // if strings.Contains(protocol, "http") { // log.Println(username, password) diff --git a/plugin/task-account-unlock-plugin.go b/plugin/task-account-unlock-plugin.go index bea6424..347aca7 100644 --- a/plugin/task-account-unlock-plugin.go +++ b/plugin/task-account-unlock-plugin.go @@ -78,7 +78,7 @@ func unlockWork(task *paramsTypes.Task, id int64) { defer func() { if r := recover(); r != nil { log.Printf("Goroutine panic: %v\nStack: %s", r, debug.Stack()) - // AccountService.ChangeAccountLoginStatus(int(id), "账号下线") + AccountService.ChangeAccountLoginStatus(int(id), "账号下线") // TwitterService.Logout(int(id)) } }() diff --git a/router/twitter.go b/router/twitter.go index 936a747..ff52318 100644 --- a/router/twitter.go +++ b/router/twitter.go @@ -15,4 +15,5 @@ func (*Twitter) TwitterRouterInit(app *gin.Engine) { twitter.POST("/register", twitterApi.Register) twitter.GET("/login", twitterApi.Login) // 登录账号 twitter.GET("/logout", twitterApi.Logout) // 退出登录 + twitter.POST("/register1", twitterApi.Register1) } diff --git a/services/bit_browser_service.go b/services/bit_browser_service.go index 07b49fa..e4741c4 100644 --- a/services/bit_browser_service.go +++ b/services/bit_browser_service.go @@ -35,24 +35,64 @@ type BitCookieParam struct { func (*BitBrowserService) CreateBrowser(proxy *models.Proxy, cookies []*proto.NetworkCookieParam) string { fingerprint := map[string]interface{}{ - "name": fmt.Sprintf(`推特注册%s`, utils.RandString(10)), - "proxyMethod": 2, - "proxyType": "noproxy", - "host": "", - "port": 0, - "proxyUserName": "", - "proxyPassword": "", - "randomFingerprint": true, - "syncTabs": false, - "syncCookies": false, + "name": fmt.Sprintf(`推特注册%s`, utils.RandString(10)), + "proxyMethod": 2, + "proxyType": "noproxy", + "host": "", + "port": 0, + "proxyUserName": "", + "proxyPassword": "", + "randomFingerprint": true, + "syncTabs": false, + "syncCookies": false, "browserFingerPrint": map[string]interface{}{ - "coreVersion": "130", - "ostype": "PC", - "os": "Win32", - "osVersion": "11,10", - "openWidth": 1920, - "openHeight": 1480, - "resolutionType": "0", + // "coreVersion": "130", + // "ostype": "PC", + // "os": "Win32", + // "osVersion": "11,10", + // "openWidth": 1920, + // "openHeight": 1480, + // "resolutionType": "0", + // "userAgent": "", // ua,不填则自动生成 + // "isIpCreateTimeZone": true, // 基于IP生成对应的时区 + // "timeZone": "", // 时区,isIpCreateTimeZone 为false时,参考附录中的时区列表 + // "timeZoneOffset": 0, // isIpCreateTimeZone 为false时设置,时区偏移量 + // "webRTC": "3", //webrtc 0 => 替换, 1 => 允许, 2 => 禁止, 3 => 隐私 + // "ignoreHttpsErrors": false, // 忽略https证书错误,true, false + // "position": "1", //地理位置 0 => 询问, 1 => 允许, 2 => 禁止 + // "isIpCreatePosition": true, // 是否基于IP生成对应的地理位置 + // "lat": "", // 纬度 isIpCreatePosition 为false时设置 + // "lng": "", // 经度 isIpCreatePosition 为false时设置 + // "precisionData": "", //精度米 isIpCreatePosition 为false时设置 + // "isIpCreateLanguage": true, // 是否基于IP生成对应国家的浏览器语言 + // "languages": "", // isIpCreateLanguage 为false时设置,值参考附录 + // "isIpCreateDisplayLanguage": true, // 是否基于IP生成对应国家的浏览器界面语言 + // "displayLanguages": "", // isIpCreateDisplayLanguage 为false时设置,默认为空,即跟随系统,值参考附录 + // "windowSizeLimit": true, // 分辨率类型为自定义,且ostype为PC时,此项有效,约束窗口最大尺寸不超过分辨率 + // "devicePixelRatio": 1, // 显示缩放比例,默认1,填写时,建议 1, 1.5, 2, 2.5, 3 + // "fontType": "2", // 字体生成类型 0 => 系统默认 | 2 => 随机 + // "canvas": "0", //canvas 0随机|1关闭 + // "webGL": "0", //webGL图像,0随机|1关闭 + // "webGLMeta": "0", //webgl元数据 0自定义|1关闭 + // "webGLManufacturer": "", // webGLMeta 自定义时,webGL厂商值,建议留空会自动生成 + // "webGLRender": "", // webGLMeta自定义时,webGL渲染值,建议留空自动生成 + // "audioContext": "0", // audioContext值,0随机|1关闭 + // "mediaDevice": "0", // 媒体设备,0 随机 | 1 关闭 + // "speechVoices": "0", // Speech Voices,0随机|1关闭 + // "hardwareConcurrency": "4", // 硬件并发数 + // "deviceMemory": "8", // 设备内存,4,8,不要传入大于8的值 + // "doNotTrack": "1", // doNotTrack 1开启|0关闭 + // "clientRectNoiseEnabled": true, // ClientRects true使用相匹配的值代替您真实的ClientRects | false每个浏览器使用当前电脑默认的ClientRects + // "portScanProtect": "0", // 端口扫描保护 0开启|1关闭,注意默认开启保护,组织所有本地127的ws链接,比如某些打印机之类的,如有连接本地服务需求,建议关闭,或者在 portWhiteList 中,填写对应端口,加入白名单 + // "portWhiteList": "", // 端口扫描保护开启时的白名单,逗号分隔 + // "deviceInfoEnabled": true, // 自定义设备信息,默认开启 + // "computerName": "", // deviceInfoEnabled 为true时设置,建议留空系统自动生成即可 + // "macAddr": "", // deviceInfoEnabled 为true时设置,建议留空系统自动生成即可 + // "disableSslCipherSuitesFlag": false, // ssl是否禁用特性,默认不禁用,注意开启后自定义设置时,有可能会导致某些网站无法访问 + // "disableSslCipherSuites": nil, // ssl 禁用特性,序列化的ssl特性值,参考附录 + // "enablePlugins": false, // 是否启用插件指纹 + // "plugins": "", // enablePlugins为true时,序列化的插件值,插件指纹值参考附录 + // "launchArgs": "", // 启动参数,如无痕模式打开,那么设置启动参数为 "--incognito", 多个启动参数用逗号分隔,如 "--incognito,--no-sandbox" }, } if cookies != nil { @@ -228,16 +268,31 @@ func (bit *BitBrowserService) Register() *libs.ErrorInfo { // 随机生成生日 dateParams := utils.RandDate(18, 80) dateSelects, _ := page.Timeout(5 * time.Second).Elements(`select.r-30o5oe.r-1niwhzg.r-17gur6a.r-1yadl64.r-18jsvk2.r-1loqt21.r-1inkyih.r-rjixqe.r-crgep1.r-1wzrnnt.r-1ny4l3l.r-t60dpp.r-xd6kpl.r-is05cd.r-ttdzmv`) - // 月份 + log.Println(dateSelects) + fmt.Println(strconv.Itoa(dateParams.Month)) + fmt.Println(strconv.Itoa(dateParams.Day)) + fmt.Println(strconv.Itoa(dateParams.Year)) + /// 月份 dateSelects[0].WaitVisible() - dateSelects[0].MustSelect(strconv.Itoa(dateParams.Month)) - // 日期 - dateSelects[1].WaitVisible() - dateSelects[1].MustSelect(strconv.Itoa(dateParams.Day)) + opts, _ := dateSelects[0].Elements("option") + for i, opt := range opts { + txt, _ := opt.Text() + val, _ := opt.Attribute("value") + log.Printf("option[%d] text=%s value=%s\n", i, txt, *val) + if i != 0 && i == dateParams.Month { + dateSelects[0].MustSelect(txt) + } + } // 年份 dateSelects[2].WaitVisible() dateSelects[2].MustSelect(strconv.Itoa(dateParams.Year)) - + // 日期 + dateSelects[1].WaitVisible() + dateSelects[1].MustSelect(strconv.Itoa(dateParams.Day)) + // dateSelects[0].MustClick() + // monthOption := dateSelects[0].MustElement(fmt.Sprintf(`option[value="%d"]`, dateParams.Month)) + // monthOption.MustClick() + time.Sleep(2 * time.Second) // 点击下一步 ocfSignupNextLink := page.Timeout(5 * time.Second).MustElement(`button[data-testid="ocfSignupNextLink"]`) ocfSignupNextLink.MustClick() @@ -282,7 +337,7 @@ func (bit *BitBrowserService) Register() *libs.ErrorInfo { page.MustNavigate("https://x.com").MustWaitLoad() time.Sleep(10 * time.Second) // 获取cookie - cookieArr := getPageCookie(page, "https://x.com") + cookieArr := GetPageCookie(page, "https://x.com") // 创建用户 twitterAccountService := InitTwitterAccountService() twitterAccountService.Create(&models.TwitterAccount{ @@ -303,14 +358,51 @@ func (bit *BitBrowserService) Register() *libs.ErrorInfo { emailService.Update(emailInfo.Email, models.Email{ UseStatus: 1, }) - // 删除浏览器 - bit.DeleteBrowser(browserId) - return libs.ErrorCode["RegisterSuccessful"] + // 设置fa2 + page.MustNavigate("https://x.com/settings/account/login_verification").MustWaitLoad() + // 点击fa2按钮 + inputCheckbox := page.Timeout(5 * time.Second).MustElement(`input[aria-describedby="CHECKBOX_2_LABEL"]`) + inputCheckbox.MustClick() + // 等待2秒 + time.Sleep(2 * time.Second) + // 设置密码 + inpurPassword, errPassword := page.Timeout(5 * time.Second).Element(`input[name="password"]`) + if errPassword == nil { + inpurPassword.MustInput(emailInfo.Password) + // 点击确认 + faConfirm := page.Timeout(5 * time.Second).MustElement(`button[data-testid="LoginForm_Login_Button"]`) + faConfirm.MustClick() + } + // 等待2秒 + time.Sleep(2 * time.Second) + ActionListNextButton := page.Timeout(5 * time.Second).MustElement(`button[data-testid="ActionListNextButton"]`) + ActionListNextButton.MustClick() + // 点击无法扫描二维码 + queryCode := page.Timeout(5 * time.Second).MustElement("div.css-175oi2r.r-1awozwy.r-w7s2jr>div.css-175oi2r.r-95jzfe>div.css-146c3p1.r-bcqeeo.r-1ttztb7.r-qvutc0.r-37j5jr.r-a023e6.r-rjixqe.r-16dba41>button.css-1jxf684.r-bcqeeo.r-qvutc0.r-poiln3.r-fdjqy7") + queryCode.MustClick() + fa2Code := page.Timeout(5 * time.Second).MustElement(`div.css-146c3p1.r-bcqeeo.r-qvutc0.r-37j5jr.r-1blvdjr.r-vrz42v.r-b88u0q.r-x572qd.r-ywje51.r-1oqcu8e.r-q4m81j.r-13qz1uu`) + fa2CodeText := fa2Code.MustText() + log.Println("当前账号的二步验证码,", fa2CodeText) + ocfShowCodeNextLink := page.Timeout(5 * time.Second).MustElement(`button[data-testid="ocfShowCodeNextLink"]`) + ocfShowCodeNextLink.MustClick() + codeText, _ := utils.GetFA2Code(fa2CodeText) + ocfEnterTextTextInput := page.Timeout(5 * time.Second).MustElement(`input[data-testid="ocfEnterTextTextInput"]`) + ocfEnterTextTextInput.MustInput(codeText) + ocfEnterTextNextButton := page.Timeout(5 * time.Second).MustElement(`button[data-testid="ocfEnterTextNextButton"]`) + ocfEnterTextNextButton.MustClick() + OCF_CallToAction_Button, errOCF := page.Timeout(5 * time.Second).Element(`button[data-testid="OCF_CallToAction_Button"]`) + if errOCF == nil { + OCF_CallToAction_Button.MustClick() + } + + // 删除浏览器 + // bit.DeleteBrowser(browserId) + return libs.ErrorCode["RegisterSuccessful"] } // 获取指定页面的cookie列表 -func getPageCookie(page *rod.Page, url string) []*proto.NetworkCookieParam { +func GetPageCookie(page *rod.Page, url string) []*proto.NetworkCookieParam { cookieArr, _ := page.Cookies([]string{url}) var cookies []*proto.NetworkCookieParam for _, cookie := range cookieArr { diff --git a/services/twitter_service.go b/services/twitter_service.go index 51e0ae0..3392dc2 100644 --- a/services/twitter_service.go +++ b/services/twitter_service.go @@ -5,11 +5,15 @@ import ( "errors" "fmt" "go-account-register/libs" + "go-account-register/models" + "go-account-register/utils" "log" + "strconv" "time" "github.com/go-rod/rod" "github.com/go-rod/rod/lib/cdp" + "github.com/go-rod/rod/lib/proto" ) type TwitterService struct{} @@ -26,8 +30,28 @@ func (*TwitterService) Login(id int) *libs.ErrorInfo { err3 := rod.Try(func() { // 创建 Cookie 对象 - cookies := user.Cookies - log.Println("获取cookie", cookies) + // cookies := user.Cookies + // log.Println("获取cookie", cookies) + // b, _ := json.MarshalIndent(cookies, "", " ") + // log.Println(string(b)) + var token string + for _, v := range user.Cookies { + if v.Name == "auth_token" { + token = v.Value + } + } + log.Println("当前账号Token", token) + cookies := []*proto.NetworkCookieParam{ + { + Name: "auth_token", + Value: token, + Domain: ".x.com", + Path: "/", + Expires: proto.TimeSinceEpoch(time.Now().Add(24 * time.Hour).Unix()), // 过期时间 + HTTPOnly: true, // 禁止 JS 访问 + Secure: true, // 仅 HTTPS 传输 + }, + } // 全局设置 browser.SetCookies(cookies) page.MustNavigate("https://x.com/home").MustWaitLoad() @@ -86,3 +110,171 @@ func (*TwitterService) Login(id int) *libs.ErrorInfo { func (*TwitterService) Logout(id int) { Browser.CancelBrowser(id) } + +func (bit *TwitterService) Register() *libs.ErrorInfo { + // 随机获取代理 + proxyService := InitProxyService() + proxy := proxyService.GetInfo() + + // 获取一个邮箱 + emailService := InitEmailService() + + emailInfo := emailService.GetEmailOne() + log.Println("当前邮箱信息", emailInfo) + obj := Browser.GetNewBrowser(&libs.Fingerprint{}) + page := obj.Page + page.MustNavigate("https://x.com/").MustWaitLoad() + // 点击创建账号 + createAccountA := page.Timeout(5 * time.Second).MustElement(`a[data-testid="signupButton"]`) + createAccountA.MustClick() + + // // 点击创建账号 + // createAccount := page.Timeout(5 * time.Second).MustElement(`button.css-175oi2r.r-sdzlij.r-1phboty.r-rs99b7.r-lrvibr.r-ywje51.r-184id4b.r-13qz1uu.r-2yi16.r-1qi8awa.r-3pj75a.r-1loqt21.r-o7ynqc.r-6416eg.r-1ny4l3l`) + // createAccount.MustClick() + // 判断当前是否是邮箱注册 + // _, err := page.Element(`input[name="email"]`) + // if err != nil { + switchButton := page.Timeout(5 * time.Second).MustElement(`button.css-146c3p1.r-bcqeeo.r-qvutc0.r-37j5jr.r-1ff274t.r-a023e6.r-rjixqe.r-16dba41`) + switchButton.MustClick() + // } + // 获取邮箱输入框 + inputEmail := page.Timeout(5 * time.Second).MustElement(`input[name="email"]`) + inputEmail.MustFocus() + inputEmail.MustInput(emailInfo.Email) + // 获取名称输入框 + inputName := page.Timeout(5 * time.Second).MustElement(`input[name="name"]`) + inputName.MustFocus() + nameStr := emailInfo.Name + if emailInfo.Name == "" { + nameStr = utils.RandString(12) + } + inputName.MustInput(nameStr) + // 随机生成生日 + dateParams := utils.RandDate(18, 80) + dateSelects, _ := page.Timeout(5 * time.Second).Elements(`select.r-30o5oe.r-1niwhzg.r-17gur6a.r-1yadl64.r-18jsvk2.r-1loqt21.r-1inkyih.r-rjixqe.r-crgep1.r-1wzrnnt.r-1ny4l3l.r-t60dpp.r-xd6kpl.r-is05cd.r-ttdzmv`) + log.Println(dateSelects) + fmt.Println(strconv.Itoa(dateParams.Month)) + fmt.Println(strconv.Itoa(dateParams.Day)) + fmt.Println(strconv.Itoa(dateParams.Year)) + time.Sleep(2 * time.Second) + // 月份 + dateSelects[0].WaitVisible() + opts, _ := dateSelects[0].Elements("option") + for i, opt := range opts { + txt, _ := opt.Text() + val, _ := opt.Attribute("value") + log.Printf("option[%d] text=%s value=%s\n", i, txt, *val) + if i != 0 && i == dateParams.Month { + dateSelects[0].MustSelect(txt) + } + } + // 年份 + dateSelects[2].WaitVisible() + dateSelects[2].MustSelect(strconv.Itoa(dateParams.Year)) + time.Sleep(2 * time.Second) + // 日期 + dateSelects[1].WaitVisible() + dateSelects[1].MustSelect(strconv.Itoa(dateParams.Day)) + // dateSelects[0].MustClick() + // monthOption := dateSelects[0].MustElement(fmt.Sprintf(`option[value="%d"]`, dateParams.Month)) + // monthOption.MustClick() + time.Sleep(2 * time.Second) + // 点击下一步 + ocfSignupNextLink := page.Timeout(5 * time.Second).MustElement(`button[data-testid="ocfSignupNextLink"]`) + ocfSignupNextLink.MustClick() + // 判断是否需要验证码 + time.Sleep(4 * time.Second) + _, err1 := page.Timeout(5 * time.Second).Element(`input[name="verfication_code"]`) + if err1 != nil { + // res := getApiResponse(page, "") + } + //TODO 对接获取邮箱信息接口 + time.Sleep(10 * time.Second) + codeValue := LoopGetEmailCode("pop.dragonsmail.com:993", emailInfo.Email, emailInfo.Password) + if codeValue == "0" { + emailService.Update(emailInfo.Email, models.Email{ + Status: 0, + }) + return libs.ErrorCode["MailboxUnavailable"] + } + // 获取邮箱验证码 + log.Println("获取当前验证码", codeValue) + codeInput1, _ := page.Timeout(5 * time.Second).Element(`input[name="verfication_code"]`) + codeInput1.MustInput(codeValue) + time.Sleep(2 * time.Second) + // 点击下一步 + codeNextButton := page.Timeout(5 * time.Second).MustElement(`button.css-175oi2r.r-sdzlij.r-1phboty.r-rs99b7.r-lrvibr.r-19yznuf.r-64el8z.r-1fkl15p.r-1loqt21.r-o7ynqc.r-6416eg.r-1ny4l3l`) + codeNextButton.MustClick() + // // 点击验证按钮 + // verifyButton := page.Timeout(5 * time.Second).MustElement(`button[data-theme="home.verifyButton"]`) + // verifyButton.MustClick() + // 输入密码 + passwordInput, err2 := page.Timeout(5 * time.Second).Element(`input[name="password"]`) + if err2 != nil { + // res := getApiResponse(page, "") + } + + passwordInput.MustInput(emailInfo.Password) + time.Sleep(5 * time.Second) + // 点击下一步 + loginButton := page.Timeout(5 * time.Second).MustElement(`button[data-testid="LoginForm_Login_Button"]`) + loginButton.MustClick() + time.Sleep(5 * time.Second) + page.MustNavigate("https://x.com").MustWaitLoad() + time.Sleep(10 * time.Second) + // 获取cookie + cookieArr := GetPageCookie(page, "https://x.com") + // 创建用户 + twitterAccountService := InitTwitterAccountService() + twitterAccountService.Create(&models.TwitterAccount{ + Name: nameStr, + Email: emailInfo.Email, + Password: emailInfo.Password, + Birthday: strconv.Itoa(dateParams.Year) + "-" + strconv.Itoa(dateParams.Month) + "-" + strconv.Itoa(dateParams.Day), + Cookies: cookieArr, + Status: "注册成功", + LoginStatus: "登录成功", + Proxy: func() string { + if proxy != nil && proxy.Type != "" { + return proxy.Type + "://" + proxy.Proxy + } + return "" + }(), + }) + emailService.Update(emailInfo.Email, models.Email{ + UseStatus: 1, + }) + // 设置fa2 + page.MustNavigate("https://x.com/settings/account/login_verification").MustWaitLoad() + // 点击fa2按钮 + inputCheckbox := page.Timeout(5 * time.Second).MustElement(`input[aria-describedby="CHECKBOX_2_LABEL"]`) + inputCheckbox.MustClick() + // 等待2秒 + time.Sleep(2 * time.Second) + // 设置密码 + inpurPassword := page.Timeout(5 * time.Second).MustElement(`input[name="password"]`) + inpurPassword.MustInput(emailInfo.Password) + // 点击确认 + faConfirm := page.Timeout(5 * time.Second).MustElement(`button[data-testid="LoginForm_Login_Button"]`) + faConfirm.MustClick() + // 等待2秒 + time.Sleep(2 * time.Second) + ActionListNextButton := page.Timeout(5 * time.Second).MustElement(`button[data-testid="ActionListNextButton"]`) + ActionListNextButton.MustClick() + // 点击无法扫描二维码 + queryCode := page.Timeout(5 * time.Second).MustElement("div.css-175oi2r.r-1awozwy.r-w7s2jr>div.css-175oi2r.r-95jzfe>div.css-146c3p1.r-bcqeeo.r-1ttztb7.r-qvutc0.r-37j5jr.r-a023e6.r-rjixqe.r-16dba41>button.css-1jxf684.r-bcqeeo.r-qvutc0.r-poiln3.r-fdjqy7") + queryCode.MustClick() + fa2Code := page.Timeout(5 * time.Second).MustElement(`div.css-146c3p1.r-bcqeeo.r-qvutc0.r-37j5jr.r-1blvdjr.r-vrz42v.r-b88u0q.r-x572qd.r-ywje51.r-1oqcu8e.r-q4m81j.r-13qz1uu`) + fa2CodeText := fa2Code.MustText() + log.Println("当前账号的二步验证码,", fa2CodeText) + ocfShowCodeNextLink := page.Timeout(5 * time.Second).MustElement(`button[data-testid="ocfShowCodeNextLink"]`) + ocfShowCodeNextLink.MustClick() + codeText, _ := utils.GetFA2Code(fa2CodeText) + ocfEnterTextTextInput := page.Timeout(5 * time.Second).MustElement(`input[data-testid="ocfEnterTextTextInput"]`) + ocfEnterTextTextInput.MustInput(codeText) + ocfEnterTextNextButton := page.Timeout(5 * time.Second).MustElement(`button[data-testid="ocfEnterTextNextButton"]`) + ocfEnterTextNextButton.MustClick() + // 删除浏览器 + return libs.ErrorCode["RegisterSuccessful"] + +} diff --git a/utils/index.go b/utils/index.go index ce463d7..6989375 100644 --- a/utils/index.go +++ b/utils/index.go @@ -2,7 +2,10 @@ package utils import ( "math/rand" + "strings" "time" + + "github.com/pquerna/otp/totp" ) type RandDateParams struct { @@ -73,3 +76,18 @@ func RandDate(minAge, maxAge int) RandDateParams { Day: day, } } + +// 获取FA2码 +func GetFA2Code(secret string) (string, error) { + // 去除多余的字符串 + replacer := strings.NewReplacer( + "-", "", + " ", "", + ) + result := replacer.Replace(secret) + code, err := totp.GenerateCode(result, time.Now()) + if err != nil { + return "", err + } + return code, nil +}