You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
72 lines
2.3 KiB
72 lines
2.3 KiB
|
2 months ago
|
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)
|
||
|
|
}
|