From 89622235533bc7dd98eb1502f306ea6ec4e57b92 Mon Sep 17 00:00:00 2001 From: Radon Rosborough Date: Mon, 26 Jan 2026 13:51:47 -0800 Subject: [PATCH 1/6] phonenumber --- go.mod | 1 + go.sum | 2 ++ pkg/messagix/bloks/interp.go | 4 ---- pkg/messagix/bloks/selenium.go | 29 +++++++++++++++++++++++++---- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 075b470..3c724e7 100644 --- a/go.mod +++ b/go.mod @@ -37,6 +37,7 @@ require ( github.com/lib/pq v1.10.9 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.33 // indirect + github.com/nyaruka/phonenumbers v1.6.8 // indirect github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 // indirect github.com/rs/xid v1.6.0 // indirect github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect diff --git a/go.sum b/go.sum index 1276daa..ec91ca4 100644 --- a/go.sum +++ b/go.sum @@ -42,6 +42,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.33 h1:A5blZ5ulQo2AtayQ9/limgHEkFreKj1Dv226a1K73s0= github.com/mattn/go-sqlite3 v1.14.33/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/nyaruka/phonenumbers v1.6.8 h1:k7HAJ/LeBkXE0vfbajITzTCZD0z0j+epdBNx43yTygk= +github.com/nyaruka/phonenumbers v1.6.8/go.mod h1:IUu45lj2bSeYXQuxDyyuzOrdV10tyRa1YSsfH8EKN5c= github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 h1:KPpdlQLZcHfTMQRi6bFQ7ogNO0ltFT4PmtwTLW4W+14= github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/pkg/messagix/bloks/interp.go b/pkg/messagix/bloks/interp.go index cf65912..281ede3 100644 --- a/pkg/messagix/bloks/interp.go +++ b/pkg/messagix/bloks/interp.go @@ -11,7 +11,6 @@ import ( "time" "github.com/google/uuid" - "go.mau.fi/util/random" ) type InterpBridge struct { @@ -91,9 +90,6 @@ func NewInterpreter(ctx context.Context, b *BloksBundle, br *InterpBridge, old * if br.FamilyDeviceID == "" { br.FamilyDeviceID = strings.ToUpper(uuid.New().String()) } - if br.MachineID == "" { - br.MachineID = string(random.StringBytes(24)) - } if br.EncryptPassword == nil { br.EncryptPassword = func(pw string) (string, error) { return fmt.Sprintf( diff --git a/pkg/messagix/bloks/selenium.go b/pkg/messagix/bloks/selenium.go index 2e48149..10d8e82 100644 --- a/pkg/messagix/bloks/selenium.go +++ b/pkg/messagix/bloks/selenium.go @@ -9,6 +9,7 @@ import ( "time" "github.com/google/uuid" + "github.com/nyaruka/phonenumbers" "github.com/rs/zerolog" "go.mau.fi/util/random" "maunium.net/go/mautrix/bridgev2" @@ -238,9 +239,24 @@ func NewBrowser(ctx context.Context, cfg *BrowserConfig) *Browser { Config: cfg, } b.Bridge = &InterpBridge{ - DeviceID: strings.ToUpper(uuid.New().String()), - FamilyDeviceID: strings.ToUpper(uuid.New().String()), - MachineID: string(random.StringBytes(24)), + DeviceID: strings.ToUpper(uuid.New().String()), + FamilyDeviceID: strings.ToUpper(uuid.New().String()), + // Note: machine_id is set to an empty string the first time the user ever logs in + // to any account on a given physical device. After a successful login, the login + // response payload contains a new machine_id that is stored in shady locations that + // the user can never normally clear even after uninstalling all their apps, and + // used for all subsequent login attempts to enable persistent tracking across + // multiple accounts on the same physical device. + // + // We do not replicate the second part of that behavior. However, doing so means + // phone number login does not work, as phone number logins are rejected without a + // valid machine_id. Note that this implies that the official app is unable to do + // phone number login, either, unless you've previously logged in a different way + // (to any account) on the same device. Yes, I tested that. + // + // The machine_id would generally be a 24 character alphanumeric string. However it + // cannot be generated on the client side so this fact is purely informational. + MachineID: "", EncryptPassword: cfg.EncryptPassword, DoRPC: func(name string, params map[string]string, isPage bool, callback func(result *BloksScriptLiteral) error) error { log.Debug().Str("state", string(b.State)).Str("rpc", name).Msg("Invoking RPC from Bloks") @@ -460,7 +476,12 @@ func (b *Browser) DoLoginStep(ctx context.Context, userInput map[string]string) break } - err := b.CurrentPage. + _, err := phonenumbers.Parse(userInput["username"], "US") + if err == nil { + return nil, fmt.Errorf("Phone number login on a new device is blocked by Facebook") + } + + err = b.CurrentPage. FindDescendant(FilterByAttribute("bk.components.TextInput", "html_name", "email")). FillInput(ctx, b.CurrentPage.Interpreter, userInput["username"]) if err != nil { From 98d330688bfbb6b2954cc9a351bcb1269c0da513 Mon Sep 17 00:00:00 2001 From: Radon Rosborough Date: Mon, 26 Jan 2026 13:58:50 -0800 Subject: [PATCH 2/6] ok --- pkg/messagix/bloks/selenium.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/messagix/bloks/selenium.go b/pkg/messagix/bloks/selenium.go index 10d8e82..65b5e16 100644 --- a/pkg/messagix/bloks/selenium.go +++ b/pkg/messagix/bloks/selenium.go @@ -478,7 +478,7 @@ func (b *Browser) DoLoginStep(ctx context.Context, userInput map[string]string) _, err := phonenumbers.Parse(userInput["username"], "US") if err == nil { - return nil, fmt.Errorf("Phone number login on a new device is blocked by Facebook") + return nil, fmt.Errorf("phone number login on a new device is blocked by Facebook") } err = b.CurrentPage. From ed6c03f2b4c7037f2a96e909fb7d33b046b0ad18 Mon Sep 17 00:00:00 2001 From: Radon Rosborough Date: Tue, 27 Jan 2026 08:14:46 -0800 Subject: [PATCH 3/6] remove dep --- go.mod | 1 - go.sum | 2 -- pkg/messagix/bloks/selenium.go | 9 +++++---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 3c724e7..075b470 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,6 @@ require ( github.com/lib/pq v1.10.9 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.33 // indirect - github.com/nyaruka/phonenumbers v1.6.8 // indirect github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 // indirect github.com/rs/xid v1.6.0 // indirect github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect diff --git a/go.sum b/go.sum index ec91ca4..1276daa 100644 --- a/go.sum +++ b/go.sum @@ -42,8 +42,6 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.33 h1:A5blZ5ulQo2AtayQ9/limgHEkFreKj1Dv226a1K73s0= github.com/mattn/go-sqlite3 v1.14.33/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/nyaruka/phonenumbers v1.6.8 h1:k7HAJ/LeBkXE0vfbajITzTCZD0z0j+epdBNx43yTygk= -github.com/nyaruka/phonenumbers v1.6.8/go.mod h1:IUu45lj2bSeYXQuxDyyuzOrdV10tyRa1YSsfH8EKN5c= github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 h1:KPpdlQLZcHfTMQRi6bFQ7ogNO0ltFT4PmtwTLW4W+14= github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/pkg/messagix/bloks/selenium.go b/pkg/messagix/bloks/selenium.go index 65b5e16..a7a427e 100644 --- a/pkg/messagix/bloks/selenium.go +++ b/pkg/messagix/bloks/selenium.go @@ -5,11 +5,11 @@ import ( "encoding/hex" "encoding/json" "fmt" + "regexp" "strings" "time" "github.com/google/uuid" - "github.com/nyaruka/phonenumbers" "github.com/rs/zerolog" "go.mau.fi/util/random" "maunium.net/go/mautrix/bridgev2" @@ -378,6 +378,8 @@ func NewBrowser(ctx context.Context, cfg *BrowserConfig) *Browser { return &b } +var usernameOrEmailRegexp = regexp.MustCompile(`^([a-zA-Z0-9]+|.+@.+)$`) + func (b *Browser) DoLoginStep(ctx context.Context, userInput map[string]string) (step *bridgev2.LoginStep, err error) { log := zerolog.Ctx(ctx) { @@ -476,9 +478,8 @@ func (b *Browser) DoLoginStep(ctx context.Context, userInput map[string]string) break } - _, err := phonenumbers.Parse(userInput["username"], "US") - if err == nil { - return nil, fmt.Errorf("phone number login on a new device is blocked by Facebook") + if !usernameOrEmailRegexp.MatchString(userInput["username"]) { + return nil, fmt.Errorf("only username or email login is allowed, not phone number") } err = b.CurrentPage. From 37f5abfa511eda1e4f9755c78f0ae950267a26f9 Mon Sep 17 00:00:00 2001 From: Radon Rosborough Date: Tue, 27 Jan 2026 08:20:40 -0800 Subject: [PATCH 4/6] require letter --- pkg/messagix/bloks/selenium.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/messagix/bloks/selenium.go b/pkg/messagix/bloks/selenium.go index a7a427e..248a899 100644 --- a/pkg/messagix/bloks/selenium.go +++ b/pkg/messagix/bloks/selenium.go @@ -378,7 +378,7 @@ func NewBrowser(ctx context.Context, cfg *BrowserConfig) *Browser { return &b } -var usernameOrEmailRegexp = regexp.MustCompile(`^([a-zA-Z0-9]+|.+@.+)$`) +var usernameOrEmailRegexp = regexp.MustCompile(`^([a-zA-Z0-9]+[a-zA-Z][a-zA-Z0-9]*|[a-zA-Z0-9]*[a-zA-Z][a-zA-Z0-9]+|.+@.+)$`) func (b *Browser) DoLoginStep(ctx context.Context, userInput map[string]string) (step *bridgev2.LoginStep, err error) { log := zerolog.Ctx(ctx) From 331ae2f55aa71ae67533b6e31f2b06f8a1d43688 Mon Sep 17 00:00:00 2001 From: Radon Rosborough Date: Tue, 27 Jan 2026 08:22:05 -0800 Subject: [PATCH 5/6] periods --- pkg/messagix/bloks/selenium.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/messagix/bloks/selenium.go b/pkg/messagix/bloks/selenium.go index 248a899..ad5874a 100644 --- a/pkg/messagix/bloks/selenium.go +++ b/pkg/messagix/bloks/selenium.go @@ -378,7 +378,7 @@ func NewBrowser(ctx context.Context, cfg *BrowserConfig) *Browser { return &b } -var usernameOrEmailRegexp = regexp.MustCompile(`^([a-zA-Z0-9]+[a-zA-Z][a-zA-Z0-9]*|[a-zA-Z0-9]*[a-zA-Z][a-zA-Z0-9]+|.+@.+)$`) +var usernameOrEmailRegexp = regexp.MustCompile(`^([a-zA-Z0-9.]+[a-zA-Z][a-zA-Z0-9.]*|[a-zA-Z0-9.]*[a-zA-Z][a-zA-Z0-9.]+|.+@.+)$`) func (b *Browser) DoLoginStep(ctx context.Context, userInput map[string]string) (step *bridgev2.LoginStep, err error) { log := zerolog.Ctx(ctx) From b94a7b55d20e2dfefac80526244334fb2b86cdbe Mon Sep 17 00:00:00 2001 From: Radon Rosborough Date: Tue, 27 Jan 2026 08:36:39 -0800 Subject: [PATCH 6/6] tweak the regex --- pkg/messagix/bloks/selenium.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/messagix/bloks/selenium.go b/pkg/messagix/bloks/selenium.go index ad5874a..c0023ea 100644 --- a/pkg/messagix/bloks/selenium.go +++ b/pkg/messagix/bloks/selenium.go @@ -378,7 +378,7 @@ func NewBrowser(ctx context.Context, cfg *BrowserConfig) *Browser { return &b } -var usernameOrEmailRegexp = regexp.MustCompile(`^([a-zA-Z0-9.]+[a-zA-Z][a-zA-Z0-9.]*|[a-zA-Z0-9.]*[a-zA-Z][a-zA-Z0-9.]+|.+@.+)$`) +var definitelyNotPhoneNumberRegexp = regexp.MustCompile(`^.*[@a-zA-Z].*$`) func (b *Browser) DoLoginStep(ctx context.Context, userInput map[string]string) (step *bridgev2.LoginStep, err error) { log := zerolog.Ctx(ctx) @@ -478,7 +478,7 @@ func (b *Browser) DoLoginStep(ctx context.Context, userInput map[string]string) break } - if !usernameOrEmailRegexp.MatchString(userInput["username"]) { + if !definitelyNotPhoneNumberRegexp.MatchString(userInput["username"]) { return nil, fmt.Errorf("only username or email login is allowed, not phone number") }