Skip to content

Commit 905d8d9

Browse files
committed
feat: update api to host update.xml and retrive .crx
1 parent 7a4f031 commit 905d8d9

File tree

3 files changed

+93
-10
lines changed

3 files changed

+93
-10
lines changed

images/chromium-headful/run-docker.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ RUN_ARGS=(
6363
-e WIDTH=1920
6464
-e TZ=${TZ:-'America/Los_Angeles'}
6565
-e RUN_AS_ROOT="$RUN_AS_ROOT"
66-
--mount type=bind,src="$FLAGS_FILE",dst=/chromium/flags,ro
66+
--mount type=bind,src="$FLAGS_FILE",dst=/chromium/flags
6767
)
6868

6969
if [[ -n "${PLAYWRIGHT_ENGINE:-}" ]]; then

server/cmd/api/api/chromium.go

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,34 @@ func (s *ApiService) UploadExtensionsAndRestart(ctx context.Context, request oap
157157
log.Error("failed to chown extension dir", "error", err)
158158
return oapi.UploadExtensionsAndRestart500JSONResponse{InternalErrorJSONResponse: oapi.InternalErrorJSONResponse{Message: "failed to chown extension dir"}}, nil
159159
}
160+
161+
// Check if the zip contains update.xml and .crx files (for policy-installed extensions)
162+
// If they exist, they'll be extracted; if not, they need to be generated separately
163+
updateXMLPath := filepath.Join(dest, "update.xml")
164+
crxPath := filepath.Join(dest, p.name+".crx")
165+
hasUpdateXML := false
166+
hasCRX := false
167+
168+
if _, err := os.Stat(updateXMLPath); err == nil {
169+
hasUpdateXML = true
170+
log.Info("found update.xml in extension zip", "name", p.name)
171+
}
172+
if _, err := os.Stat(crxPath); err == nil {
173+
hasCRX = true
174+
log.Info("found .crx file in extension zip", "name", p.name)
175+
}
176+
177+
if !hasUpdateXML || !hasCRX {
178+
log.Info("extension zip missing update.xml or .crx - these files should be included for policy-installed extensions", "name", p.name, "hasUpdateXML", hasUpdateXML, "hasCRX", hasCRX)
179+
}
180+
160181
log.Info("installed extension", "name", p.name)
161182
}
162183

163184
// Update enterprise policy for extensions that require it
185+
// Track which extensions need --load-extension flags (those NOT using policy installation)
186+
var pathsNeedingFlags []string
187+
164188
for _, p := range items {
165189
extensionPath := filepath.Join(extBase, p.name)
166190
extensionID := s.policy.GenerateExtensionID(p.name)
@@ -175,6 +199,9 @@ func (s *ApiService) UploadExtensionsAndRestart(ctx context.Context, request oap
175199

176200
if requiresEntPolicy {
177201
log.Info("extension requires enterprise policy", "name", p.name)
202+
} else {
203+
// Only add --load-extension flags for non-policy extensions
204+
pathsNeedingFlags = append(pathsNeedingFlags, extensionPath)
178205
}
179206

180207
// Add to enterprise policy
@@ -191,15 +218,13 @@ func (s *ApiService) UploadExtensionsAndRestart(ctx context.Context, request oap
191218
}
192219

193220
// Build flags overlay file in /chromium/flags, merging with existing flags
194-
var paths []string
195-
for _, p := range items {
196-
paths = append(paths, filepath.Join(extBase, p.name))
197-
}
198-
199-
// Create new flags for the uploaded extensions
200-
newTokens := []string{
201-
fmt.Sprintf("--disable-extensions-except=%s", strings.Join(paths, ",")),
202-
fmt.Sprintf("--load-extension=%s", strings.Join(paths, ",")),
221+
// Only add --load-extension flags for extensions that don't use policy installation
222+
var newTokens []string
223+
if len(pathsNeedingFlags) > 0 {
224+
newTokens = []string{
225+
fmt.Sprintf("--disable-extensions-except=%s", strings.Join(pathsNeedingFlags, ",")),
226+
fmt.Sprintf("--load-extension=%s", strings.Join(pathsNeedingFlags, ",")),
227+
}
203228
}
204229

205230
// Merge and write flags

server/cmd/api/main.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,64 @@ func main() {
124124
apiService.HandleProcessAttach(w, r, id)
125125
})
126126

127+
// Serve extension files for Chrome policy-installed extensions
128+
// This allows Chrome to download .crx and update.xml files via HTTP
129+
extensionsDir := "/home/kernel/extensions"
130+
r.Get("/extensions/*", func(w http.ResponseWriter, r *http.Request) {
131+
// Serve files from /home/kernel/extensions/
132+
fs := http.StripPrefix("/extensions/", http.FileServer(http.Dir(extensionsDir)))
133+
fs.ServeHTTP(w, r)
134+
})
135+
136+
// Serve update.xml at root for Chrome enterprise policy
137+
// This serves the first update.xml found in any extension directory
138+
r.Get("/update.xml", func(w http.ResponseWriter, r *http.Request) {
139+
// Try to find update.xml in the first extension directory
140+
entries, err := os.ReadDir(extensionsDir)
141+
if err != nil {
142+
http.Error(w, "extensions directory not found", http.StatusNotFound)
143+
return
144+
}
145+
146+
for _, entry := range entries {
147+
if entry.IsDir() {
148+
updateXMLPath := fmt.Sprintf("%s/%s/update.xml", extensionsDir, entry.Name())
149+
if _, err := os.Stat(updateXMLPath); err == nil {
150+
http.ServeFile(w, r, updateXMLPath)
151+
return
152+
}
153+
}
154+
}
155+
156+
http.Error(w, "update.xml not found", http.StatusNotFound)
157+
})
158+
159+
// Serve CRX files at root for Chrome enterprise policy
160+
// This allows simple codebase URLs like http://host:port/extension-name.crx
161+
r.Get("/{filename}.crx", func(w http.ResponseWriter, r *http.Request) {
162+
// Extract the filename from the URL path
163+
filename := chi.URLParam(r, "filename") + ".crx"
164+
165+
// Search for the CRX file in all extension directories
166+
entries, err := os.ReadDir(extensionsDir)
167+
if err != nil {
168+
http.Error(w, "extensions directory not found", http.StatusNotFound)
169+
return
170+
}
171+
172+
for _, entry := range entries {
173+
if entry.IsDir() {
174+
crxPath := fmt.Sprintf("%s/%s/%s", extensionsDir, entry.Name(), filename)
175+
if _, err := os.Stat(crxPath); err == nil {
176+
http.ServeFile(w, r, crxPath)
177+
return
178+
}
179+
}
180+
}
181+
182+
http.Error(w, "crx file not found", http.StatusNotFound)
183+
})
184+
127185
srv := &http.Server{
128186
Addr: fmt.Sprintf(":%d", config.Port),
129187
Handler: r,

0 commit comments

Comments
 (0)