func GetSuggestion(w rest.ResponseWriter, r *rest.Request) { ID := r.PathParam("id") form, ok := client.GetSuggestion(ID) if !ok { apiutils.WriteRestError(w, apierrors.NewNotFound("suggestion", ID)) return } w.WriteJson(form) }
// Prepared returns true if no othesamples are expected to be added func (s Suggestion) Prepared() (bool, error) { s, ok := GetSuggestion(s.ID) if !ok { return false, apierrors.NewNotFound("suggestion", s.ID) } if s.Token == "" { return false, apierrors.NewConflict("suggestion", "", errors.New("No session token associated with suggestion")) } return s.prepared, nil }
func DeleteConnection(w rest.ResponseWriter, r *rest.Request) { ID := r.PathParam("id") err := clientconfig.Update(func(conf *clientconfig.Config) error { all := conf.Settings.Connections var result []shared.Connection // validate that the id exists found := false nEnabled := 0 for _, v := range all { if v.ID == ID { found = true if v.Protected { apiutils.WriteRestError(w, apierrors.NewForbidden("connection", ID, nil)) return nil } } else { if !v.Disabled { nEnabled += 1 } result = append(result, v) } } if !found { apiutils.WriteRestError(w, apierrors.NewNotFound("connection", ID)) return nil } if nEnabled < 1 { apiutils.WriteRestError(w, apierrors.NewForbidden("connection", ID, errors.New("one connection must be enabled"))) return nil } service.UpdateConnections(result) conf.Settings.Connections = result return nil }) if err != nil { lg.Errorln(err) } clientconfig.Write() w.WriteJson(true) }
func ToggleConnection(w rest.ResponseWriter, r *rest.Request) { ID := r.PathParam("id") err := clientconfig.Update(func(conf *clientconfig.Config) error { // validate that the id exists, if supplied all := conf.Settings.Connections foundIdx := 0 found := false nEnabled := 0 for k, v := range all { if !v.Disabled { nEnabled += 1 } if v.ID == ID { found = true foundIdx = k } } if !found { apiutils.WriteRestError(w, apierrors.NewNotFound("connection", ID)) return nil } if nEnabled < 2 && !conf.Settings.Connections[foundIdx].Disabled { apiutils.WriteRestError(w, apierrors.NewForbidden("connection", ID, errors.New("one connection must be enabled"))) return nil } conf.Settings.Connections[foundIdx].Disabled = !conf.Settings.Connections[foundIdx].Disabled service.UpdateConnections(conf.Settings.Connections) return nil }) if err != nil { lg.Errorln(err) } clientconfig.Write() w.WriteJson(true) }
// AddSample adds a sample to the local cache ready to be sent to central using SendSamples. func (sugg *Suggestion) SendSamples(client *Client) (int, error) { s, ok := GetSuggestion(sugg.ID) if !ok { return 0, apierrors.NewNotFound("suggestion", sugg.ID) } if s.Token == "" { return 0, apierrors.NewConflict("suggestion", "", errors.New("No session token associated with suggestion")) } n := 0 var rerr error for _, v := range s.samples { r, err := client.CreateSample(shared.StoreSampleRequest{ Sample: &shared.Sample{ Token: s.Token, SampleType: v.sampleType, Data: v.data, URL: s.URL, }, ClientAddr: shared.GetPublicIPAddr().String(), }) if err != nil { rerr = errors.New("error sending sample: " + err.Error()) continue } if !r.Ok { rerr = errors.New("error sending sample, not accepted") continue } n++ modifySuggestion <- removeSample(s, v) } return n, rerr }
// SubmitSuggestion initiates the comminication with Central for a Submission // session. func SubmitSuggestion(w rest.ResponseWriter, r *rest.Request) { // // TODO This is the response that must be forwarded from central/api and parsed by client and passed on to the browser. // apiutils.WriteRestError(w, // apierrors.NewInvalid("object", "suggestion", // fielderrors.ValidationErrorList{ // fielderrors.NewFieldValueNotSupported("URL", "...", []string{})})) // return ID := r.PathParam("id") suggestion, ok := client.GetSuggestion(ID) if !ok { apiutils.WriteRestError(w, apierrors.NewNotFound("suggestion", ID)) return } wanip := shared.GetPublicIPAddr() if wanip == nil { lg.Warning("could not resolve public ip addr") } conf := clientconfig.Get() restclient, err := NewRestClient() if err != nil { apiutils.WriteRestError(w, apierrors.NewInternalError(err)) return } tokenResp, err := suggestion.RequestToken( restclient, wanip, conf.Settings.Local.CountryCode) if err != nil { if apiutils.IsNetError(err) { apiutils.WriteRestError(w, apierrors.NewServerTimeout("alkasir-central", "request-submission-token", 0)) } else { apiutils.WriteRestError(w, apierrors.NewInternalError(err)) } return } n, err := suggestion.SendSamples(restclient) if err != nil { lg.Warningln("error sending samples", err.Error()) } lg.V(5).Infof("sent %d samples", n) // continue sending samples if future measuremetns are expected to come prepared, err := suggestion.Prepared() if err != nil { lg.Errorln(err) } else if !prepared { lg.V(5).Infof("all samples not collected, will try to send the rest when they are done") go func(s client.Suggestion) { start := time.Now() t := time.NewTicker(30 * time.Second) defer t.Stop() submitSamples: for range t.C { if time.Now().After(start.Add(15 * time.Minute)) { lg.Errorln("Stopping trying to send additional samples") return } prepared, err := suggestion.Prepared() if err != nil { lg.Errorln(err) return } if prepared { restclient, err := NewRestClient() if err != nil { continue submitSamples } n, err := suggestion.SendSamples(restclient) lg.V(5).Infof("sent %d samples", n) if err != nil { lg.Warningln("error sending samples", err.Error()) continue submitSamples } return } } }(suggestion) } u, err := url.Parse(suggestion.URL) if err != nil { lg.Errorln(err) } else { err := clientconfig.Update(func(conf *clientconfig.Config) error { conf.BlockedHosts.Add(u.Host) lastBlocklistChange = time.Now() pac.UpdateBlockedList(conf.BlockedHostsCentral.Hosts, conf.BlockedHosts.Hosts) return nil }) if err != nil { lg.Errorln(err) } } w.WriteJson(tokenResp) }
// SubmitSuggestion initiates the comminication with Central for a Submission // session. func SubmitSuggestion(w rest.ResponseWriter, r *rest.Request) { // // TODO This is the response that must be forwarded from central/api and parsed by client and passed on to the browser. // apiutils.WriteRestError(w, // apierrors.NewInvalid("object", "suggestion", // fielderrors.ValidationErrorList{ // fielderrors.NewFieldValueNotSupported("URL", "...", []string{})})) // return ID := r.PathParam("id") suggestion, ok := client.GetSuggestion(ID) if !ok { apiutils.WriteRestError(w, apierrors.NewNotFound("suggestion", ID)) return } wanip := shared.GetPublicIPAddr() if wanip == nil { lg.Warning("could not resolve public ip addr") } conf := clientconfig.Get() restclient, err := NewRestClient() if err != nil { apiutils.WriteRestError(w, apierrors.NewInternalError(err)) return } tokenResp, err := suggestion.RequestToken( restclient, wanip, conf.Settings.Local.CountryCode) if err != nil { if apiutils.IsNetError(err) { apiutils.WriteRestError(w, apierrors.NewServerTimeout("alkasir-central", "request-submission-token", 0)) } else { apiutils.WriteRestError(w, apierrors.NewInternalError(err)) } return } n, err := suggestion.SendSamples(restclient) if err != nil { lg.Warningln("error sending samples", err.Error()) } lg.V(5).Infoln("sent ", n) // FIXME PRESENTATION: just add the url locally u, err := url.Parse(suggestion.URL) if err != nil { lg.Errorln(err) } else { err := clientconfig.Update(func(conf *clientconfig.Config) error { conf.BlockedHosts.Add(u.Host) lastBlocklistChange = time.Now() pac.UpdateBlockedList(conf.BlockedHostsCentral.Hosts, conf.BlockedHosts.Hosts) return nil }) if err != nil { lg.Errorln(err) } } w.WriteJson(tokenResp) }
// Update list of blocked hosts for an IP address. func GetUpgrade(dbclients db.Clients) func(w rest.ResponseWriter, r *rest.Request) { return func(w rest.ResponseWriter, r *rest.Request) { req := shared.BinaryUpgradeRequest{} err := r.DecodeJsonPayload(&req) // TODO: proper validation response if err != nil { apiError(w, err.Error(), http.StatusInternalServerError) return } if req.FromVersion == "" { apiError(w, "fromversion required", http.StatusInternalServerError) return } v, err := version.NewVersion(req.FromVersion) if err != nil { lg.Warningln(err) apiError(w, fmt.Sprintf("invalid fromVersion %s", req.FromVersion), http.StatusInternalServerError) return } if req.Artifact == "" { apiError(w, "artifact required", http.StatusInternalServerError) return } res, found, err := dbclients.DB.GetUpgrade( db.GetUpgradeQuery{ Artifact: req.Artifact, }) if err != nil { apiError(w, err.Error(), http.StatusInternalServerError) return } if !found { apiutils.WriteRestError(w, apierrors.NewNotFound( "upgrade", fmt.Sprintf("%s-%s", req.Artifact, req.FromVersion))) return } serverVersion, err := version.NewVersion(res.Version) if err != nil { apiError(w, err.Error(), http.StatusInternalServerError) return } if serverVersion.LessThan(v) || serverVersion.Equal(v) { apiutils.WriteRestError(w, apierrors.NewNotFound( "upgrade", fmt.Sprintf("%s-%s", req.Artifact, req.FromVersion))) return } w.WriteJson(shared.BinaryUpgradeResponse{ Artifact: res.Artifact, Version: res.Version, CreatedAt: res.CreatedAt, SHA256Sum: res.SHA256Sum, ED25519Signature: res.ED25519Signature, }) } }