package handlers import ( "context" "encoding/json" "io" "net/http" "net/url" "strings" "time" ) type loginStartupStatus struct { ClockSyncToken string `json:"clock_sync_token,omitempty"` Ready bool `json:"ready"` State string `json:"state"` ElapsedMS int64 `json:"elapsed_ms"` Completed int `json:"completed"` Total int `json:"total"` Stages []struct { ID string `json:"id"` Label string `json:"label"` State string `json:"state"` } `json:"stages"` CaptchaEnabled bool `json:"captcha_enabled"` } func (h *DeviceHandler) handleBootstrapTime(w http.ResponseWriter, r *http.Request) { w.Header().Set("Cache-Control", "no-store") // Custom header + JSON require a CORS preflight for cross-origin browsers. if r.Method != http.MethodPost || r.Header.Get("X-Clock-Bootstrap") != "1" || !strings.HasPrefix(r.Header.Get("Content-Type"), "application/json") { http.Error(w, "invalid clock initialization request", http.StatusForbidden) return } if origin := r.Header.Get("Origin"); origin != "" { u, err := url.Parse(origin) if err != nil || u.Host != r.Host || (u.Scheme != "http" && u.Scheme != "https") { http.Error(w, "invalid origin", http.StatusForbidden) return } } ctx, cancel := context.WithTimeout(r.Context(), 6*time.Second) defer cancel() r.Body = http.MaxBytesReader(w, r.Body, 1024) payload, err := io.ReadAll(r.Body) if err != nil { http.Error(w, "invalid body", http.StatusBadRequest) return } endpoint := h.apiTarget.ResolveReference(&url.URL{Path: "/api/v1/auth/bootstrap-time"}) request, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), strings.NewReader(string(payload))) if err != nil { http.Error(w, "clock service unavailable", 502) return } request.Header.Set("Content-Type", "application/json") response, err := h.apiClient.Do(request) if err != nil { http.Error(w, "clock service unavailable", 502) return } defer response.Body.Close() w.Header().Set("Content-Type", "application/json") w.WriteHeader(response.StatusCode) _, _ = io.Copy(w, io.LimitReader(response.Body, 4096)) } func writeStartupResponse(w http.ResponseWriter, state loginStartupStatus) { w.Header().Set("Content-Type", "application/json; charset=utf-8") _ = json.NewEncoder(w).Encode(state) }