detached db4efc4

Honor unsafe WebAuthn override

commit
db4efc48421e6d4ba381e625081ef0cdc0fcee73
author
brice · · 2026-04-29 17:41 UTC
parent
27813e6
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +82 -1
M internal/infrastructure/cef/app.go +48 -1
@@ -54,7 +54,12 @@ func configureCommandLine(commandLine purecef.CommandLine) {
5454 }
5555
5656 func configureWebAuthnFeaturePolicy(commandLine purecef.CommandLine) {
57- if commandLine == nil || cefWebAuthnUnsafeEnabled() {
57+ if commandLine == nil {
58+ return
59+ }
60+ if cefWebAuthnUnsafeEnabled() {
61+ removeCommaSeparatedSwitchValues(commandLine, chromiumDisableFeaturesSwitch, cefWebAuthnFeaturesDisabledByPolicy...)
62+ removeCommaSeparatedSwitchValues(commandLine, chromiumDisableBlinkFeaturesSwitch, cefWebAuthnFeaturesDisabledByPolicy...)
5863 return
5964 }
6065 appendUniqueCommaSeparatedSwitchValues(commandLine, chromiumDisableFeaturesSwitch, cefWebAuthnFeaturesDisabledByPolicy...)
@@ -97,6 +102,48 @@ func appendUniqueCommaSeparatedSwitchValues(commandLine purecef.CommandLine, nam
97102 commandLine.AppendSwitchWithValue(name, strings.Join(combined, ","))
98103 }
99104
105+func removeCommaSeparatedSwitchValues(commandLine purecef.CommandLine, name string, values ...string) {
106+ if commandLine == nil || len(values) == 0 {
107+ return
108+ }
109+
110+ existing := commandLine.GetSwitchValue(name)
111+ if existing == "" {
112+ return
113+ }
114+
115+ removeSet := make(map[string]struct{}, len(values))
116+ for _, v := range values {
117+ removeSet[strings.TrimSpace(v)] = struct{}{}
118+ }
119+
120+ tokens := strings.Split(existing, ",")
121+ cleaned := make([]string, 0, len(tokens))
122+ removed := false
123+ for _, token := range tokens {
124+ token = strings.TrimSpace(token)
125+ if token == "" {
126+ continue
127+ }
128+ if _, ok := removeSet[token]; ok {
129+ removed = true
130+ continue
131+ }
132+ cleaned = append(cleaned, token)
133+ }
134+
135+ if !removed {
136+ return
137+ }
138+
139+ if len(cleaned) == 0 {
140+ commandLine.RemoveSwitch(name)
141+ return
142+ }
143+
144+ commandLine.AppendSwitchWithValue(name, strings.Join(cleaned, ","))
145+}
146+
100147 // dumberApp implements purecef.App to provide custom scheme registration,
101148 // command-line configuration, and browser-process lifecycle callbacks.
102149 type dumberApp struct {
@@ -54,7 +54,12 @@ func configureCommandLine(commandLine purecef.CommandLine) {
54 }54 }
55 55
56 func configureWebAuthnFeaturePolicy(commandLine purecef.CommandLine) {56 func configureWebAuthnFeaturePolicy(commandLine purecef.CommandLine) {
57- if commandLine == nil || cefWebAuthnUnsafeEnabled() {57+ if commandLine == nil {
58+ return
59+ }
60+ if cefWebAuthnUnsafeEnabled() {
61+ removeCommaSeparatedSwitchValues(commandLine, chromiumDisableFeaturesSwitch, cefWebAuthnFeaturesDisabledByPolicy...)
62+ removeCommaSeparatedSwitchValues(commandLine, chromiumDisableBlinkFeaturesSwitch, cefWebAuthnFeaturesDisabledByPolicy...)
58 return63 return
59 }64 }
60 appendUniqueCommaSeparatedSwitchValues(commandLine, chromiumDisableFeaturesSwitch, cefWebAuthnFeaturesDisabledByPolicy...)65 appendUniqueCommaSeparatedSwitchValues(commandLine, chromiumDisableFeaturesSwitch, cefWebAuthnFeaturesDisabledByPolicy...)
@@ -97,6 +102,48 @@ func appendUniqueCommaSeparatedSwitchValues(commandLine purecef.CommandLine, nam
97 commandLine.AppendSwitchWithValue(name, strings.Join(combined, ","))102 commandLine.AppendSwitchWithValue(name, strings.Join(combined, ","))
98 }103 }
99 104
105+func removeCommaSeparatedSwitchValues(commandLine purecef.CommandLine, name string, values ...string) {
106+ if commandLine == nil || len(values) == 0 {
107+ return
108+ }
109+
110+ existing := commandLine.GetSwitchValue(name)
111+ if existing == "" {
112+ return
113+ }
114+
115+ removeSet := make(map[string]struct{}, len(values))
116+ for _, v := range values {
117+ removeSet[strings.TrimSpace(v)] = struct{}{}
118+ }
119+
120+ tokens := strings.Split(existing, ",")
121+ cleaned := make([]string, 0, len(tokens))
122+ removed := false
123+ for _, token := range tokens {
124+ token = strings.TrimSpace(token)
125+ if token == "" {
126+ continue
127+ }
128+ if _, ok := removeSet[token]; ok {
129+ removed = true
130+ continue
131+ }
132+ cleaned = append(cleaned, token)
133+ }
134+
135+ if !removed {
136+ return
137+ }
138+
139+ if len(cleaned) == 0 {
140+ commandLine.RemoveSwitch(name)
141+ return
142+ }
143+
144+ commandLine.AppendSwitchWithValue(name, strings.Join(cleaned, ","))
145+}
146+
100 // dumberApp implements purecef.App to provide custom scheme registration,147 // dumberApp implements purecef.App to provide custom scheme registration,
101 // command-line configuration, and browser-process lifecycle callbacks.148 // command-line configuration, and browser-process lifecycle callbacks.
102 type dumberApp struct {149 type dumberApp struct {
M internal/infrastructure/cef/app_test.go +34 -0
@@ -188,6 +188,8 @@ func TestConfigureCommandLine_AppendsExpectedSwitches(t *testing.T) {
188188 }
189189
190190 func TestConfigureCommandLine_DisablesWebAuthnByDefault(t *testing.T) {
191+ t.Setenv(cefEnableWebAuthnUnsafeEnvVar, "")
192+
191193 commandLine := newMutableCommandLineStub()
192194 configureCommandLine(commandLine)
193195
@@ -229,6 +231,36 @@ func TestConfigureCommandLine_WebAuthnDisablePreservesExistingDisableFeatures(t
229231 }
230232 }
231233
234+func TestConfigureCommandLine_WebAuthnUnsafeOverrideRemovesExistingWebAuthTokens(t *testing.T) {
235+ t.Setenv(cefEnableWebAuthnUnsafeEnvVar, "1")
236+
237+ commandLine := newMutableCommandLineStub()
238+ commandLine.AppendSwitchWithValue(chromiumDisableFeaturesSwitch, "ExistingFeature,WebAuth,AnotherFeature")
239+ commandLine.AppendSwitchWithValue(chromiumDisableBlinkFeaturesSwitch, "WebAuth,ExistingBlinkFeature")
240+
241+ configureCommandLine(commandLine)
242+
243+ if got := commandLine.GetSwitchValue(chromiumDisableFeaturesSwitch); got != "ExistingFeature,AnotherFeature" {
244+ t.Fatalf("disable-features = %q, want %q", got, "ExistingFeature,AnotherFeature")
245+ }
246+ if got := commandLine.GetSwitchValue(chromiumDisableBlinkFeaturesSwitch); got != "ExistingBlinkFeature" {
247+ t.Fatalf("disable-blink-features = %q, want %q", got, "ExistingBlinkFeature")
248+ }
249+}
250+
251+func TestConfigureCommandLine_WebAuthnUnsafeOverrideRemovesSwitchWhenOnlyWebAuth(t *testing.T) {
252+ t.Setenv(cefEnableWebAuthnUnsafeEnvVar, "1")
253+
254+ commandLine := newMutableCommandLineStub()
255+ commandLine.AppendSwitchWithValue(chromiumDisableFeaturesSwitch, "WebAuth")
256+
257+ configureCommandLine(commandLine)
258+
259+ if commandLine.HasSwitch(chromiumDisableFeaturesSwitch) {
260+ t.Fatalf("disable-features switch should have been removed entirely, but has value %q", commandLine.GetSwitchValue(chromiumDisableFeaturesSwitch))
261+ }
262+}
263+
232264 func TestAppendUniqueCommaSeparatedSwitchValues(t *testing.T) {
233265 t.Run("trims whitespace and skips empty existing values", func(t *testing.T) {
234266 commandLine := newMutableCommandLineStub()
@@ -282,6 +314,8 @@ func TestDumberBPH_OnBeforeChildProcessLaunch_AppendsNoZygote(t *testing.T) {
282314 }
283315
284316 func TestDumberBPH_OnBeforeChildProcessLaunch_DisablesWebAuthnByDefault(t *testing.T) {
317+ t.Setenv(cefEnableWebAuthnUnsafeEnvVar, "")
318+
285319 commandLine := newMutableCommandLineStub()
286320 commandLine.AppendSwitchWithValue("type", "renderer")
287321
@@ -188,6 +188,8 @@ func TestConfigureCommandLine_AppendsExpectedSwitches(t *testing.T) {
188 }188 }
189 189
190 func TestConfigureCommandLine_DisablesWebAuthnByDefault(t *testing.T) {190 func TestConfigureCommandLine_DisablesWebAuthnByDefault(t *testing.T) {
191+ t.Setenv(cefEnableWebAuthnUnsafeEnvVar, "")
192+
191 commandLine := newMutableCommandLineStub()193 commandLine := newMutableCommandLineStub()
192 configureCommandLine(commandLine)194 configureCommandLine(commandLine)
193 195
@@ -229,6 +231,36 @@ func TestConfigureCommandLine_WebAuthnDisablePreservesExistingDisableFeatures(t
229 }231 }
230 }232 }
231 233
234+func TestConfigureCommandLine_WebAuthnUnsafeOverrideRemovesExistingWebAuthTokens(t *testing.T) {
235+ t.Setenv(cefEnableWebAuthnUnsafeEnvVar, "1")
236+
237+ commandLine := newMutableCommandLineStub()
238+ commandLine.AppendSwitchWithValue(chromiumDisableFeaturesSwitch, "ExistingFeature,WebAuth,AnotherFeature")
239+ commandLine.AppendSwitchWithValue(chromiumDisableBlinkFeaturesSwitch, "WebAuth,ExistingBlinkFeature")
240+
241+ configureCommandLine(commandLine)
242+
243+ if got := commandLine.GetSwitchValue(chromiumDisableFeaturesSwitch); got != "ExistingFeature,AnotherFeature" {
244+ t.Fatalf("disable-features = %q, want %q", got, "ExistingFeature,AnotherFeature")
245+ }
246+ if got := commandLine.GetSwitchValue(chromiumDisableBlinkFeaturesSwitch); got != "ExistingBlinkFeature" {
247+ t.Fatalf("disable-blink-features = %q, want %q", got, "ExistingBlinkFeature")
248+ }
249+}
250+
251+func TestConfigureCommandLine_WebAuthnUnsafeOverrideRemovesSwitchWhenOnlyWebAuth(t *testing.T) {
252+ t.Setenv(cefEnableWebAuthnUnsafeEnvVar, "1")
253+
254+ commandLine := newMutableCommandLineStub()
255+ commandLine.AppendSwitchWithValue(chromiumDisableFeaturesSwitch, "WebAuth")
256+
257+ configureCommandLine(commandLine)
258+
259+ if commandLine.HasSwitch(chromiumDisableFeaturesSwitch) {
260+ t.Fatalf("disable-features switch should have been removed entirely, but has value %q", commandLine.GetSwitchValue(chromiumDisableFeaturesSwitch))
261+ }
262+}
263+
232 func TestAppendUniqueCommaSeparatedSwitchValues(t *testing.T) {264 func TestAppendUniqueCommaSeparatedSwitchValues(t *testing.T) {
233 t.Run("trims whitespace and skips empty existing values", func(t *testing.T) {265 t.Run("trims whitespace and skips empty existing values", func(t *testing.T) {
234 commandLine := newMutableCommandLineStub()266 commandLine := newMutableCommandLineStub()
@@ -282,6 +314,8 @@ func TestDumberBPH_OnBeforeChildProcessLaunch_AppendsNoZygote(t *testing.T) {
282 }314 }
283 315
284 func TestDumberBPH_OnBeforeChildProcessLaunch_DisablesWebAuthnByDefault(t *testing.T) {316 func TestDumberBPH_OnBeforeChildProcessLaunch_DisablesWebAuthnByDefault(t *testing.T) {
317+ t.Setenv(cefEnableWebAuthnUnsafeEnvVar, "")
318+
285 commandLine := newMutableCommandLineStub()319 commandLine := newMutableCommandLineStub()
286 commandLine.AppendSwitchWithValue("type", "renderer")320 commandLine.AppendSwitchWithValue("type", "renderer")
287 321

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close