Skip to content

Commit b4ab4e3

Browse files
committed
wire to cli and opt
1 parent 64a06a4 commit b4ab4e3

8 files changed

Lines changed: 187 additions & 7 deletions

File tree

auth/option.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,17 @@ func RODWithUserAgent(ua string) Option {
8787
}
8888
}
8989

90+
// RODWithBundledBrowser forces the launcher-managed bundled Chromium to be
91+
// used for all browser-based login flows, overriding system browser
92+
// auto-detection. Callers that set this to true should also call
93+
// [RODWithInteractiveBrowserAuto](false) to suppress the system-browser
94+
// detection added in issue #675.
95+
func RODWithBundledBrowser(b bool) Option {
96+
return func(o *options) {
97+
o.rodOpts.bundledBrowser = b
98+
}
99+
}
100+
90101
// RODWithInteractiveBrowserAuto controls whether the [auth_ui.LInteractive]
91102
// "Login in Browser" flow opportunistically uses a locally installed
92103
// system browser (Chrome/Edge/Brave/Chromium) instead of the bundled

auth/rod_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,25 @@ import (
2222
"github.com/rusq/slackauth"
2323
)
2424

25+
func TestRODWithBundledBrowser(t *testing.T) {
26+
tests := []struct {
27+
name string
28+
b bool
29+
}{
30+
{name: "sets true", b: true},
31+
{name: "sets false", b: false},
32+
}
33+
for _, tt := range tests {
34+
t.Run(tt.name, func(t *testing.T) {
35+
var o options
36+
RODWithBundledBrowser(tt.b)(&o)
37+
if o.rodOpts.bundledBrowser != tt.b {
38+
t.Errorf("RODWithBundledBrowser(%v): bundledBrowser = %v, want %v", tt.b, o.rodOpts.bundledBrowser, tt.b)
39+
}
40+
})
41+
}
42+
}
43+
2544
func TestFindInteractiveBrowser(t *testing.T) {
2645
tests := []struct {
2746
name string

cmd/slackdump/internal/workspace/assets/new.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,20 @@ workspace by default. You can either continue using it as your default
1313
workspace or create a new one. Later, you can switch between workspaces using
1414
the `workspace select` command.
1515

16+
## Browser selection
17+
18+
By default, `workspace new` will detect a locally installed browser (Chrome,
19+
Edge, Brave, or Chromium) and use it for the interactive "Login in Browser"
20+
flow. This is the recommended behaviour because the launcher-managed bundled
21+
Chromium is pinned to an older revision that Slack now rejects.
22+
23+
If a system browser causes problems (or none is installed), use
24+
`-bundled-browser` to fall back to the launcher-managed bundled Chromium:
25+
26+
```shell
27+
slackdump workspace new -bundled-browser <workspace name or url>
28+
```
29+
1630
## Usage
1731
### Free and Standard Workspaces
1832

cmd/slackdump/internal/workspace/new.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,13 @@ func init() {
5151

5252
// runWspNew authenticates in the new workspace.
5353
func runWspNew(ctx context.Context, cmd *base.Command, args []string) error {
54+
authOpts := append([]auth.Option{
55+
auth.BrowserWithBrowser(wspcfg.Browser),
56+
auth.BrowserWithTimeout(wspcfg.LoginTimeout),
57+
}, wspcfg.RodAuthOptions()...)
58+
5459
m, err := CacheMgr(
55-
cache.WithAuthOpts(
56-
auth.BrowserWithBrowser(wspcfg.Browser),
57-
auth.BrowserWithTimeout(wspcfg.LoginTimeout),
58-
auth.RODWithRODHeadlessTimeout(wspcfg.HeadlessTimeout),
59-
auth.RODWithUserAgent(wspcfg.RODUserAgent),
60-
))
60+
cache.WithAuthOpts(authOpts...))
6161
if err != nil {
6262
base.SetExitStatus(base.SCacheError)
6363
return fmt.Errorf("error initialising workspace manager: %s", err)

cmd/slackdump/internal/workspace/workspaceui/ezlogin3000.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ func playwrightLogin(ctx context.Context, mgr manager) error {
7777
}
7878

7979
func rodLogin(ctx context.Context, mgr manager) error {
80-
prov, err := auth.NewRODAuth(ctx, auth.BrowserWithTimeout(wspcfg.LoginTimeout), auth.RODWithRODHeadlessTimeout(wspcfg.HeadlessTimeout), auth.RODWithUserAgent(wspcfg.RODUserAgent))
80+
authOpts := append([]auth.Option{
81+
auth.BrowserWithTimeout(wspcfg.LoginTimeout),
82+
}, wspcfg.RodAuthOptions()...)
83+
prov, err := auth.NewRODAuth(ctx, authOpts...)
8184
if err != nil {
8285
return err
8386
}

cmd/slackdump/internal/workspace/workspaceui/workspaceui.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,12 @@ func configuration() cfgui.Configuration {
232232
Value: wspcfg.RODUserAgent,
233233
Updater: updaters.NewString(&wspcfg.RODUserAgent, "", false, nil),
234234
},
235+
{
236+
Name: "Force Bundled Browser",
237+
Description: "Use the launcher-managed bundled Chromium instead of a system browser for interactive login.",
238+
Value: cfgui.Checkbox(wspcfg.BundledBrowser),
239+
Updater: updaters.NewBool(&wspcfg.BundledBrowser),
240+
},
235241
},
236242
},
237243
}

cmd/slackdump/internal/workspace/wspcfg/wspcfg.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,19 @@ var (
3232
LoginTimeout time.Duration = browser.DefLoginTimeout // overall login time.
3333
HeadlessTimeout time.Duration = auth.RODHeadlessTimeout // net interaction time.
3434
RODUserAgent string // when empty, slackauth uses the default user agent.
35+
BundledBrowser bool // when true, forces the launcher-managed bundled Chromium for interactive login.
3536
// playwright stuff
3637
Browser browser.Browser
3738
LegacyBrowser bool
3839
)
3940

41+
var (
42+
rodWithHeadlessTimeout = auth.RODWithRODHeadlessTimeout
43+
rodWithUserAgent = auth.RODWithUserAgent
44+
rodWithBundledBrowser = auth.RODWithBundledBrowser
45+
rodWithInteractiveAuto = auth.RODWithInteractiveBrowserAuto
46+
)
47+
4048
func SetWspFlags(fs *flag.FlagSet) {
4149
fs.StringVar(&SlackToken, "token", osenv.Secret("SLACK_TOKEN", ""), "Slack `token`")
4250
fs.StringVar(&SlackCookie, "cookie", osenv.Secret("SLACK_COOKIE", ""), "d= cookie `value` or a path to a cookie.txt file\n(environment: SLACK_COOKIE)")
@@ -45,4 +53,16 @@ func SetWspFlags(fs *flag.FlagSet) {
4553
fs.DurationVar(&HeadlessTimeout, "autologin-timeout", HeadlessTimeout, "headless autologin `timeout`, without the browser starting time, just the interaction time")
4654
fs.BoolVar(&LegacyBrowser, "legacy-browser", false, "use legacy browser automation (playwright) for EZ-Login 3000")
4755
fs.StringVar(&RODUserAgent, "user-agent", "", "override the user agent string for EZ-Login 3000")
56+
fs.BoolVar(&BundledBrowser, "bundled-browser", false, "force the launcher-managed bundled Chromium for interactive login (disables system browser auto-detection)")
57+
}
58+
59+
// RodAuthOptions returns auth options shared by all ROD-based workspace login
60+
// entry points, keeping CLI and TUI behaviour aligned.
61+
func RodAuthOptions() []auth.Option {
62+
return []auth.Option{
63+
rodWithHeadlessTimeout(HeadlessTimeout),
64+
rodWithUserAgent(RODUserAgent),
65+
rodWithBundledBrowser(BundledBrowser),
66+
rodWithInteractiveAuto(!BundledBrowser),
67+
}
4868
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Copyright (c) 2021-2026 Rustam Gilyazov and Contributors.
2+
//
3+
// This program is free software: you can redistribute it and/or modify
4+
// it under the terms of the GNU Affero General Public License as published by
5+
// the Free Software Foundation, either version 3 of the License, or
6+
// (at your option) any later version.
7+
//
8+
// This program is distributed in the hope that it will be useful,
9+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
// GNU Affero General Public License for more details.
12+
//
13+
// You should have received a copy of the GNU Affero General Public License
14+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
15+
16+
package wspcfg
17+
18+
import (
19+
"flag"
20+
"testing"
21+
"time"
22+
23+
"github.com/rusq/slackdump/v4/auth"
24+
)
25+
26+
func TestSetWspFlags_bundledBrowser(t *testing.T) {
27+
tests := []struct {
28+
name string
29+
args []string
30+
want bool
31+
}{
32+
{name: "default is false", args: []string{}, want: false},
33+
{name: "-bundled-browser sets true", args: []string{"-bundled-browser"}, want: true},
34+
{name: "-bundled-browser=true", args: []string{"-bundled-browser=true"}, want: true},
35+
{name: "-bundled-browser=false", args: []string{"-bundled-browser=false"}, want: false},
36+
}
37+
for _, tt := range tests {
38+
t.Run(tt.name, func(t *testing.T) {
39+
BundledBrowser = false
40+
fs := flag.NewFlagSet("test", flag.ContinueOnError)
41+
SetWspFlags(fs)
42+
if err := fs.Parse(tt.args); err != nil {
43+
t.Fatalf("Parse() error = %v", err)
44+
}
45+
if BundledBrowser != tt.want {
46+
t.Errorf("BundledBrowser = %v, want %v", BundledBrowser, tt.want)
47+
}
48+
})
49+
}
50+
}
51+
52+
func TestRodAuthOptions_WiresBundledBrowserPolarity(t *testing.T) {
53+
origHeadless := rodWithHeadlessTimeout
54+
origUA := rodWithUserAgent
55+
origBundled := rodWithBundledBrowser
56+
origAuto := rodWithInteractiveAuto
57+
defer func() {
58+
rodWithHeadlessTimeout = origHeadless
59+
rodWithUserAgent = origUA
60+
rodWithBundledBrowser = origBundled
61+
rodWithInteractiveAuto = origAuto
62+
}()
63+
64+
var (
65+
gotHeadless time.Duration
66+
gotUA string
67+
gotBundled bool
68+
gotAuto bool
69+
)
70+
rodWithHeadlessTimeout = func(d time.Duration) auth.Option {
71+
gotHeadless = d
72+
return nil
73+
}
74+
rodWithUserAgent = func(s string) auth.Option {
75+
gotUA = s
76+
return nil
77+
}
78+
rodWithBundledBrowser = func(b bool) auth.Option {
79+
gotBundled = b
80+
return nil
81+
}
82+
rodWithInteractiveAuto = func(b bool) auth.Option {
83+
gotAuto = b
84+
return nil
85+
}
86+
87+
HeadlessTimeout = 77 * time.Second
88+
RODUserAgent = "ua-test"
89+
BundledBrowser = true
90+
opts := RodAuthOptions()
91+
92+
if len(opts) != 4 {
93+
t.Fatalf("RodAuthOptions() len = %d, want 4", len(opts))
94+
}
95+
if gotHeadless != 77*time.Second {
96+
t.Errorf("headless timeout = %v, want %v", gotHeadless, 77*time.Second)
97+
}
98+
if gotUA != "ua-test" {
99+
t.Errorf("user agent = %q, want %q", gotUA, "ua-test")
100+
}
101+
if !gotBundled {
102+
t.Errorf("bundled browser = %v, want true", gotBundled)
103+
}
104+
if gotAuto {
105+
t.Errorf("interactive auto = %v, want false", gotAuto)
106+
}
107+
}

0 commit comments

Comments
 (0)