Beispiel #1
0
// Handler that clients can use to get a jwt token.
// Payload needs to be json in the form of {"username": "******", "password": "******"}.
// Reply will be of the form {"token": "TOKEN"}.
func (mw *JWTMiddleware) LoginHandler(writer rest.ResponseWriter, request *rest.Request) {
	login_vals := login{}
	err := request.DecodeJsonPayload(&login_vals)

	if err != nil {
		apiutils.WriteRestError(writer, apierrors.NewBadRequest(err.Error()))
		return
	}

	if login_vals.Username == "" {
		apiutils.WriteRestError(writer,
			apierrors.NewInvalid("login", "",
				fielderrors.ValidationErrorList{
					fielderrors.NewFieldRequired("username")}))
		return
	}
	if login_vals.Password == "" {
		apiutils.WriteRestError(writer,
			apierrors.NewInvalid("login", "",
				fielderrors.ValidationErrorList{
					fielderrors.NewFieldRequired("password")}))
		return
	}

	if !mw.Authenticator(login_vals.Username, login_vals.Password) {
		mw.unauthorized(writer)
		return
	}

	token := jwt.New(jwt.GetSigningMethod(mw.SigningAlgorithm))

	if mw.PayloadFunc != nil {
		for key, value := range mw.PayloadFunc(login_vals.Username) {
			token.Claims[key] = value
		}
	}

	token.Claims["id"] = login_vals.Username
	token.Claims["exp"] = time.Now().Add(mw.Timeout).Unix()
	if mw.MaxRefresh != 0 {
		token.Claims["orig_iat"] = time.Now().Unix()
	}
	tokenString, err := token.SignedString(mw.Key)

	if err != nil {
		mw.unauthorized(writer)
		return
	}

	writer.WriteJson(&map[string]string{"token": tokenString})
}
Beispiel #2
0
func PostTransportTraffic(w rest.ResponseWriter, r *rest.Request) {
	form := shared.TransportTraffic{}
	err := r.DecodeJsonPayload(&form)
	if err != nil {
		apiutils.WriteRestError(w, apierrors.NewInternalError(err))
		return
	}
	transportTrafficMu.Lock()
	defer transportTrafficMu.Unlock()
	transportTraffic = form
	if lg.V(10) {
		if len(transportTrafficLog) == 6 {
			lg.Infof("transport traffic: %.0fkb/s %.0fkb/s %.0fkb/s %.0fkb/s  %.0fkb/s %.0fkb/s",
				(transportTrafficLog[0].Throughput)/1024,
				(transportTrafficLog[1].Throughput)/1024,
				(transportTrafficLog[2].Throughput)/1024,
				(transportTrafficLog[3].Throughput)/1024,
				(transportTrafficLog[4].Throughput)/1024,
				(transportTrafficLog[5].Throughput)/1024,
			)
			transportTrafficLog = make([]shared.TransportTraffic, 0)
		}
		if transportTraffic.Throughput > 1024 {
			transportTrafficLog = append(transportTrafficLog, form)
		}
	}
	response := true
	w.WriteJson(response)
}
Beispiel #3
0
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)

}
Beispiel #4
0
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)
}
Beispiel #5
0
func PostExportChromeExtension(w rest.ResponseWriter, r *rest.Request) {

	err := saveChromeExtension()
	if err != nil {
		apiutils.WriteRestError(w, apierrors.NewInternalError(err))
		return
	}

	w.WriteJson(true)
}
Beispiel #6
0
func PostBrowsercodeToClipboard(w rest.ResponseWriter, r *rest.Request) {
	conf := clientconfig.Get()
	ak := conf.Settings.Local.ClientAuthKey
	addr := conf.Settings.Local.ClientBindAddr

	bc := browsercode.BrowserCode{Key: ak}
	err := bc.SetHostport(addr)
	if err != nil {
		apiutils.WriteRestError(w, apierrors.NewInternalError(err))
		return
	}

	err = bc.CopyToClipboard()
	if err != nil {
		apiutils.WriteRestError(w, apierrors.NewInternalError(err))
		return
	}

	w.WriteJson(true)
}
Beispiel #7
0
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)

}
Beispiel #8
0
func PostUserSettings(w rest.ResponseWriter, r *rest.Request) {
	form := UserSettings{}
	err := r.DecodeJsonPayload(&form)
	if err != nil {
		apiutils.WriteRestError(w, apierrors.NewBadRequest(err.Error()))
		return
	}

	changed := false // true if config really was updated
	err = clientconfig.Update(func(conf *clientconfig.Config) error {

		s := &conf.Settings.Local
		prevLang := s.Language
		if ValidLanguage(form.Language) {
			s.Language = form.Language
		} else {
			s.Language = "en"
		}
		if prevLang != s.Language {
			ui.Language(s.Language)
			changed = true
		}
		if s.CountryCode != form.CountryCode {
			s.CountryCode = form.CountryCode
			changed = true
		}
		if s.ClientAutoUpdate != form.ClientAutoUpdate {
			s.ClientAutoUpdate = form.ClientAutoUpdate
			changed = true
		}
		if s.BlocklistAutoUpdate != form.BlocklistAutoUpdate {
			s.BlocklistAutoUpdate = form.BlocklistAutoUpdate
			changed = true
		}

		return nil
	})
	if changed {
		err := clientconfig.Write()
		if err != nil {
			lg.Errorln(err)
		}
	}

	if err != nil {
		lg.Errorln(err)
	}

}
Beispiel #9
0
func ValidateConnectionString(w rest.ResponseWriter, r *rest.Request) {
	form := ValidateConnectionStringRequest{}
	err := r.DecodeJsonPayload(&form)
	if err != nil {
		apiutils.WriteRestError(w, apierrors.NewBadRequest("can't decode json"))
		return
	}

	c, err := shared.DecodeConnection(form.ConnectionString)

	if err != nil {
		w.WriteJson(ValidateConnectionStringResponse{
			Ok: false,
		})
		return
	}

	w.WriteJson(ValidateConnectionStringResponse{
		Ok:   true,
		Name: c.DisplayName(),
	})
}
Beispiel #10
0
func (mw *JWTMiddleware) unauthorized(writer rest.ResponseWriter) {
	writer.Header().Set("WWW-Authenticate", "JWT realm="+mw.Realm)
	apiutils.WriteRestError(writer, apierrors.NewUnauthorized(""))
}
Beispiel #11
0
// 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)
}
Beispiel #12
0
// CreateSuggestion .
func CreateSuggestion(w rest.ResponseWriter, r *rest.Request) {

	form := shared.BrowserSuggestionTokenRequest{}
	err := r.DecodeJsonPayload(&form)
	if err != nil {
		// apiError(w, err.Error(), http.StatusInternalServerError)
		apiutils.WriteRestError(w, err)
		return
	}

	var invalids fielderrors.ValidationErrorList

	// parse and validate url.
	URL := strings.TrimSpace(form.URL)
	if URL == "" {
		invalids = append(invalids, fielderrors.NewFieldRequired("URL"))
		// apiError(w, "no or empty URL", http.StatusBadRequest)

	}
	u, err := url.Parse(URL)
	if err != nil {
		invalids = append(invalids, fielderrors.NewFieldInvalid("URL", URL, err.Error()))
		// apiError(w, fmt.Sprintf("%s is not a valid URL", URL), http.StatusBadRequest)

	}

	host := u.Host
	if strings.Contains(host, ":") {
		host, _, err = net.SplitHostPort(u.Host)
		if err != nil {
			invalids = append(invalids, fielderrors.NewFieldInvalid("URL", URL, err.Error()))
		}
	}

	if !shared.AcceptedURL(u) {
		invalids = append(invalids, fielderrors.NewFieldValueNotSupported("URL", URL, nil))
	}

	if len(invalids) > 0 {
		apiutils.WriteRestError(w, apierrors.NewInvalid("create-suggestion", "URL", invalids))
		return
	}

	s := client.NewSuggestion(u.String())
	defer s.DoneAddingSamples()
	measurers, err := measure.DefaultMeasurements(form.URL)
	if err != nil {
		apiutils.WriteRestError(w, apierrors.NewInternalError(err))
		return
	}

	for _, v := range measurers {
		m, err := v.Measure()
		if err != nil {
			lg.Errorf("could not measure: %s", err.Error())
		} else {
			switch m.Type() {
			case sampletypes.DNSQuery, sampletypes.HTTPHeader:
				err = s.AddMeasurement(m)
				if err != nil {
					lg.Errorln(err.Error())
					return
				}
			default:
				lg.Warningf("unsupported sample type: %s", m.Type().String())
			}
		}
	}
}
Beispiel #13
0
func PostConnection(w rest.ResponseWriter, r *rest.Request) {
	form := ConnectionSetting{}
	err := r.DecodeJsonPayload(&form)
	if err != nil {
		apiutils.WriteRestError(w, apierrors.NewBadRequest(err.Error()))
		return
	}

	err = clientconfig.Update(func(conf *clientconfig.Config) error {

		all := conf.Settings.Connections

		var connection shared.Connection // decoded connection
		var invalids fielderrors.ValidationErrorList

		// Verify that the encoded field is set
		{
			if form.Encoded == "" {
				invalids = append(invalids, fielderrors.NewFieldRequired("encoded"))
			}
		}

		// verify that the connection is decodeable
		{
			var err error
			connection, err = shared.DecodeConnection(form.Encoded)
			if err != nil {
				invalids = append(invalids, fielderrors.NewFieldInvalid("encoded", form.Encoded, "invalid formatting"))
			}
		}

		// validate that the id exists, if supplied
		foundIdx := 0
		{
			if form.ID != "" {
				found := false
				for k, v := range all {
					if v.ID == form.ID {
						found = true
						foundIdx = k
					}
				}
				if !found {
					invalids = append(invalids, fielderrors.NewFieldNotFound("id", form.ID))
				}
			}
		}

		// validate that the connection doesnt alreay exist
		{
			encoded, err := connection.Encode()
			if err != nil {
				apiutils.WriteRestError(w, err)
				return nil
			}

			found := false
			for _, v := range all {
				enc2, err := v.Encode()
				if err != nil {
					lg.Errorln(err)
					continue
				}
				if enc2 == encoded {
					found = true
				}
			}
			if found {
				invalids = append(invalids, fielderrors.NewFieldDuplicate("encoded", form.Encoded))
			}
		}

		// end of field validations
		if len(invalids) > 0 {
			apiutils.WriteRestError(w, apierrors.NewInvalid("post-connection", "", invalids))
			return nil
		}

		// add connection to settings and save
		if form.ID == "" {
			connection.EnsureID()
			conf.Settings.Connections = append(conf.Settings.Connections, connection)
		} else {
			conf.Settings.Connections[foundIdx] = connection
		}
		service.UpdateConnections(conf.Settings.Connections)
		return nil
	})
	if err != nil {
		lg.Errorln(err)
	}
	clientconfig.Write()
	w.WriteJson(true)

}
Beispiel #14
0
// 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)
}
Beispiel #15
0
// 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,
		})

	}
}