Example #1
0
// InsertUpgrades inserts a list of upgrade entreis into the database
func (d *DB) InsertUpgrades(u []UpgradeMeta) error {
	psql := squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar)

	tx, err := d.cache.Begin()
	if err != nil {
		return err
	}

	for _, v := range u {
		i := psql.Insert("upgrades").
			Columns("artifact", "version", "sha256sum", "ed25519sig").
			Values(v.Artifact, v.Version, v.SHA256Sum, v.ED25519Signature)
		_, err := i.RunWith(d.cache).Exec()
		if err != nil {
			logSQLErr(err, &i)
			if err := tx.Rollback(); err != nil {
				lg.Errorln(err)
			}
			return err
		}
	}
	err = tx.Commit()
	if err != nil {
		lg.Errorln(err)
	}
	return nil
}
Example #2
0
// Encrypt encrypts the response using the provided hex encoded public key
func (d *DebugResponse) Encrypt(pubKey string) error {
	if pubKey == "" {
		return fmt.Errorf("pubKey must be supplied")
	}

	pk := new([32]byte)
	dpk, err := hex.DecodeString(pubKey)
	if err != nil {
		lg.Fatalln("Could not decode debug public key")
	}
	copy(pk[:], dpk[:32])
	data, err := json.Marshal(&d)
	if err != nil {
		lg.Errorln("could not marshal debug response", err)
		return nil
	}

	encrypted, err := sodiumbox.Seal(data, pk)
	if err != nil {
		lg.Errorln("could not encrypt debug response", err)
		return nil
	}

	*d = DebugResponse{
		Header:    d.Header,
		Encrypted: hex.EncodeToString(encrypted.Box),
	}

	return nil

}
Example #3
0
func upgradeBinaryCheck(diffsBaseURL string) error {
	artifactNameMu.Lock()
	artifact := artifactName
	artifactNameMu.Unlock()

	cl, err := NewRestClient()
	if err != nil {
		return err
	}

	res, found, err := cl.CheckBinaryUpgrade(shared.BinaryUpgradeRequest{
		Artifact:    artifact,
		FromVersion: VERSION,
	})
	if err != nil {
		return err
	}
	if !found {
		lg.Infoln("no update found")
		return nil
	}
	lg.Warningf("found update %+v", res)

	httpclient, err := service.NewTransportHTTPClient(2 * time.Hour)
	if err != nil {
		return err
	}

	opts, err := upgradebin.NewUpdaterOptions(res, shared.UpgradeVerificationPublicKey)
	if err != nil {
		return err
	}

	u, err := url.Parse(diffsBaseURL)
	if err != nil {
		lg.Errorln(err)
		return err
	}
	u.Path = path.Join(u.Path, artifact, VERSION, res.Version)
	URL := u.String()

	lg.Infoln("downloading", URL)
	resp, err := httpclient.Get(URL)
	if err != nil {
		lg.Errorln(err)
		return err
	}

	defer resp.Body.Close()
	err = upgradebin.Apply(resp.Body, opts)
	if err != nil {
		lg.Errorln(err)
		// will be retried the next time the client starts
		return nil
	}

	return nil

}
Example #4
0
func upgradeBinaryCheck() error {
	if !upgradeEnabled {
		lg.Infoln("binary upgrades are disabled using the command line flag")
		return nil
	}
	artifactNameMu.Lock()
	artifact := artifactName
	artifactNameMu.Unlock()

	cl, err := NewRestClient()
	if err != nil {
		return err
	}
	// TODO: check for current artifact + version (need to add artifact id to cmd's)
	res, found, err := cl.CheckBinaryUpgrade(shared.BinaryUpgradeRequest{
		Artifact:    artifact,
		FromVersion: VERSION,
	})
	if err != nil {
		return err
	}
	if !found {
		lg.Infoln("no update found")
		return nil
	}
	lg.Warningf("found update %+v", res)

	httpclient, err := service.NewTransportHTTPClient()
	if err != nil {
		return err
	}

	opts, err := upgradebin.NewUpdaterOptions(res, shared.UpgradeVerificationPublicKey)
	if err != nil {
		return err
	}

	URL := fmt.Sprintf("https://central.server.domain/u/%s/%s/%s", artifact, VERSION, res.Version)
	lg.Infoln("downloading %s", URL)
	resp, err := httpclient.Get(URL)
	if err != nil {
		lg.Errorln(err)
		return err
	}

	defer resp.Body.Close()
	err = upgradebin.Apply(resp.Body, opts)
	if err != nil {
		lg.Errorln(err)
		// will be retried the next time the client starts
		return nil
	}

	return nil

}
Example #5
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)
	}

}
Example #6
0
// StartBinaryUpgradeChecker checks for binary upgrades when the connection is
// up and on a schedule.
//
// This function runs in it's own goroutine.
func StartBinaryUpgradeChecker() {
	connectionEventListener := make(chan service.ConnectionHistory)
	uChecker, _ := NewUpdateChecker("binary")
	service.AddListener(connectionEventListener)
	for {
		select {
		// Update when the transport connection comes up
		case event := <-connectionEventListener:
			if event.IsUp() {
				uChecker.Activate()
				uChecker.UpdateNow()
			}

		// Update by request of the update checker
		case request := <-uChecker.RequestC:
			err := upgradeBinaryCheck()
			// err := fakeUpgradeBinaryCheck()
			if err != nil {
				lg.Errorln(err)
				request.ResponseC <- UpdateError
			} else {
				request.ResponseC <- UpdateSuccess
			}
		}
	}
}
Example #7
0
func (p *PreparedSample) Update(dbclients db.Clients) error {
	IP := shared.GetPublicIPAddr()
	if IP == nil {
		return errors.New("could not get own public ip address")
	}

	// resolve ip to asn.
	var ASN int
	ASNres, err := dbclients.Internet.IP2ASN(IP)
	if err != nil {
		lg.Errorln(err.Error())
		return err
	}
	if ASNres != nil {
		ASN = ASNres.ASN
	} else {
		lg.Warningf("no ASN lookup result for IP: %s ", IP)
		return fmt.Errorf("no ASN lookup result for IP: %s ", IP)
	}

	// resolve ip to country code.
	countryCode := dbclients.Maxmind.IP2CountryCode(IP)

	s := db.Sample{
		CountryCode: countryCode,
		ASN:         ASN,
	}

	p.lastUpdated = time.Now()
	p.s = s
	return nil
}
Example #8
0
func startMeasurer(dbclients db.Clients) {

	for n := 0; n < 10; n++ {

		go func() {
			var ps PreparedSample
			err := ps.Update(dbclients)
			if err != nil {
				lg.Error("could not resolve public ip address", err)
			}

			lg.V(5).Infoln("starting measurer")
			for r := range requestMeasurements {
				lg.V(50).Infoln("got measurement", r)
				if ps.lastUpdated.Before(time.Now().Add(-time.Hour * 5)) {
					lg.V(15).Info("updating prepared sample", ps)
					err := ps.Update(dbclients)
					if err != nil {
						lg.Warning(err)
					}

				}
			measurerLoop:
				for _, v := range r.measurers {
					measurement, err := v.Measure()
					if err != nil {
						lg.Errorf("could not measure:%v error:%s", v, err.Error())
						continue measurerLoop
					}
					switch measurement.Type() {
					case sampletypes.DNSQuery, sampletypes.HTTPHeader:

						data, err := measurement.Marshal()
						if err != nil {
							lg.Errorf("could not decode %v error:%s", measurement, err.Error())
							continue measurerLoop
						}
						err = dbclients.DB.InsertSample(db.Sample{
							Host:        measurement.Host(),
							CountryCode: ps.s.CountryCode,
							Token:       r.token,
							ASN:         ps.s.ASN,
							Type:        measurement.Type().String(),
							Origin:      sampleorigins.Central.String(),
							Data:        data,
						})
						if err != nil {
							lg.Errorln(err.Error())
							continue measurerLoop
						}
					default:
						lg.Errorf("could not measure:%v error:%s", v, err.Error())
						continue measurerLoop
					}
				}
			}
		}()
	}
}
Example #9
0
// UpgradeConfig updates the config, if needed.
func UpgradeConfig() (bool, error) {
	currentConrfigMu.Lock()
	defer currentConrfigMu.Unlock()
	if !currentConfig.configRead {
		return false, errors.New("config not read")
	}
	prevVer := currentConfig.Settings.Version

	switch currentConfig.Settings.Version {
	case 0: // when config file was created from template
		currentConfig.Settings.Version = 1
		fallthrough
	case 1:
		lg.Infoln("updating configuration to v1")
		m := &modifyConnections{
			Connections: currentConfig.Settings.Connections,
			Add: []string{
				"aieyJ0Ijoib2JmczQiLCJzIjoiXCJjZXJ0PUdzVFAxVmNwcjBJeE9aUkNnUHZ0Z1JsZVJWQzFTRmpYWVhxSDVvSEhYVFJ4M25QVnZXN2xHK2RkREhKWmw4YjBOVFZ1VGc7aWF0LW1vZGU9MFwiIiwiYSI6IjEzOS4xNjIuMjIxLjEyMzo0NDMifQ==",
				"aieyJ0Ijoib2JmczQiLCJzIjoiXCJjZXJ0PTMzdXNkSUVDemFyRUpsWFpQM0w0Y2x0bi9vNXdhVUlOcHRUU0JSYk5BQVpVcVlsajhiZm5MWGYyb3BFNHE2c0NlYzY3Ync7aWF0LW1vZGU9MFwiIiwiYSI6IjQ2LjIxLjEwMi4xMDk6NDQzIn0=",
			},
			Remove: []string{
				// NOTE: old hash function used, not a current format ID
				"xFa9T1i6bJMJIvK6kxFA1xvQGfW58BY3OLkrPXbpvAY=",
			},
		}
		currentConfig.Settings.Connections = m.Update()
		currentConfig.Settings.Version = 2
		fallthrough
	case 2:
		m := &modifyConnections{
			Connections: currentConfig.Settings.Connections,
			Protect: []string{
				"z0VZS-Kx9tMfoBEyX6br19GaJgKDe0IK0i6JKyhKp2s",
				"ipJ2oW8xr9TFDvfU92qGvDaPwZttf_GSjGZ4KW7inBI",
			},
			Remove: []string{
				"Ul3D2G1dI3_Z4sLXQ9IUQdIFH4pSDyNjTwf_auy93Os",
			},
		}
		currentConfig.Settings.Connections = m.Update()
		currentConfig.Settings.Version = 3
		fallthrough
	case 3:
		key := browsercode.NewKey()
		currentConfig.Settings.Local.ClientAuthKey = key
		currentConfig.Settings.Local.ClientBindAddr = "127.0.0.1:8899"
		currentConfig.Settings.Version = 4
		fallthrough
	case 4:
		lg.Infoln("Settings version", currentConfig.Settings.Version)
	default:
		lg.Errorln("Future configuration version!", currentConfig.Settings.Version)
	}
	return currentConfig.Settings.Version != prevVer, nil
}
Example #10
0
func saveChromeExtension() error {
	exportPath := filepath.Join(osutil.HomePath(), "AlkasirChromeExtension")
	if err := os.RemoveAll(exportPath); err != nil {
		lg.Errorln(err)
	}
	err := chrome.RestoreAssets(exportPath, "")
	if err != nil {
		return err
	}
	return nil

}
Example #11
0
func testPatch(pr CreatePatchResult, publicKey string) error {
	lg.Infof("verifying %s   %s>%s", pr.Artifact, pr.OldVersion, pr.NewVersion)
	tmpfile := fmt.Sprintf("/tmp/%s-%s-o", pr.Artifact, pr.OldVersion)
	err := cp(tmpfile, pr.job.OldBinary)
	if err != nil {
		lg.Fatal(err)
	}

	defer func() {
		err = os.Remove(tmpfile)
		if err != nil {
			lg.Errorln(err)
		}
	}()

	sum, err := base64.RawURLEncoding.DecodeString(pr.SHA256Sum)
	if err != nil {
		return err
	}

	sig, err := upgradebin.DecodeSignature(pr.ED25519Signature)
	if err != nil {
		return err
	}
	pub, err := upgradebin.DecodePublicKey([]byte(publicKey))
	if err != nil {
		return err
	}

	opts := update.Options{
		Patcher:    update.NewBSDiffPatcher(),
		Verifier:   upgradebin.NewED25519Verifier(),
		Hash:       crypto.SHA256,
		Checksum:   sum,
		Signature:  sig[:],
		PublicKey:  pub,
		TargetPath: tmpfile,
	}

	diffFile, err := os.Open(pr.DiffFile)
	if err != nil {
		return err
	}
	defer diffFile.Close()

	err = update.Apply(diffFile, opts)
	if err != nil {
		return err
	}

	return nil
}
Example #12
0
func listVersions([]string) error {
	for _, v := range jobQs {
		versions, err := v.GetVersions()
		if err != nil {
			lg.Errorln(err)
			continue
		}
		for _, v := range versions {
			spew.Dump(v)
		}
	}
	return nil
}
Example #13
0
func StartAnalysis(clients db.Clients) {

	tick := time.NewTicker(5 * time.Second)
	lastID, err := clients.DB.GetLastProcessedSampleID()
	if err != nil {
		lg.Warningln(err)
	}

	for n := 0; n < 4; n++ {
		go sessionFetcher(clients)
		go samplesAnalyzer()
		go hostPublisher(clients)
	}

	lg.Infof("starting analysis from sample ID %d", lastID)

	lastPersistedID := lastID

	for range tick.C {
		results, err := clients.DB.GetSamples(uint64(lastID), "")
		if err != nil {
			lg.Errorf("database err (skipping): %v", err)
			continue
		}
		n := 0
		start := time.Now()
		for s := range results {
			n++
			if s.ID > lastID {
				lastID = s.ID
			}

			if s.Origin == "Central" && s.Type == "HTTPHeader" {
				sessionFetchC <- s.Token
			}
		}
		if n != 0 && lg.V(15) {
			lg.Infof("processed %d samples in %s", n, time.Since(start).String())
		}
		if lastID != lastPersistedID {
			err = clients.DB.SetLastProcessedSampleID(lastID)
			if err != nil {
				lg.Errorln(err)
			} else {
				lastPersistedID = lastID
			}
		}
	}

}
Example #14
0
func startAnalysis(clients db.Clients) {
	go func() {
		tick := time.NewTicker(10 * time.Second)

		lastID, err := clients.DB.GetLastProcessedSampleID()
		if err != nil {
			lg.Warningln(err)
		}
		lg.Infof("starting analysis from sample ID %d", lastID)

		lastPersistedID := lastID

		for range tick.C {
			results, err := clients.DB.GetSamples(uint64(lastID), "")
			if err != nil {
				lg.Fatal(err)
			}
			n := 0
			start := time.Now()
		loop:
			for s := range results {
				n++
				if s.ID > lastID {
					lastID = s.ID
				}
				if s.Type == "NewClientToken" {
					if !shared.AcceptedHost(s.Host) {
						lg.Warningln("not accepted host id:", s.ID, s.Host)
						continue loop
					}
					err := clients.DB.PublishHost(s)
					if err != nil {
						lg.Warning(err)
					}
				}
			}
			if n != 0 && lg.V(15) {
				lg.Infof("processed %d samples in %s", n, time.Since(start).String())
			}
			if lastID != lastPersistedID {
				err = clients.DB.SetLastProcessedSampleID(lastID)
				if err != nil {
					lg.Errorln(err)
				} else {
					lastPersistedID = lastID
				}
			}
		}
	}()
}
Example #15
0
// NewDebugResponse creates a filled DebugResponse struct
func NewDebugResposne(version string, config interface{}) *DebugResponse {
	ID, err := shared.SecureRandomString(12)
	if err != nil {
		panic("could not generate random number")
	}
	response := &DebugResponse{
		Header: DebugHeader{
			Cmd:       filepath.Base(os.Args[0]),
			ID:        ID,
			Version:   version,
			CreatedAt: time.Now(),
			OS:        runtime.GOOS,
			Arch:      runtime.GOARCH,
			GoVersion: runtime.Version(),
		},
		Config: config,
	}

	getProfile := func(name string) []string {
		buf := bytes.NewBuffer(nil)
		err := pprof.Lookup(name).WriteTo(buf, 2)
		if err != nil {
			lg.Errorln(err)
		} else {
			return strings.Split(
				buf.String(),
				"\n")
		}
		return []string{}
	}

	response.Heap = getProfile("heap")
	response.GoRoutines = getProfile("goroutine")
	response.ThreadCreate = getProfile("threadcreate")
	response.Block = getProfile("block")
	// memlog should be last so that it can catch errors up to the point of
	// collection.
	response.Log = lg.Memlog()

	if PublicKey != "" {
		response.Encrypt(PublicKey)
	} else {
		lg.Warningln("PublicKey not set, exporting unencrypted debug log")
	}

	return response

}
Example #16
0
func sessionFetcher(clients db.Clients) {
loop:
	for token := range sessionFetchC {
		if token == "" {
			lg.Errorln("empty token received, skipping")
			continue loop

		}
		samples, err := clients.DB.GetSessionSamples(token)
		if err != nil {
			lg.Error(err)
			continue loop
		}
		sampleAnalysisC <- samples
	}
}
Example #17
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)

}
Example #18
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)

}
Example #19
0
func Open() error {
	ctx := usb.NewContext()
	// ctx.Debug(10)
	devs, err := ctx.ListDevices(func(desc *usb.Descriptor) bool {
		if desc.Vendor.String() == "0590" {
			return true
		}
		return false
	})
	if err != nil {
		for _, v := range devs {
			err := v.Close()
			if err != nil {
				lg.Errorln(err)
			}
		}
		return err
	}
	usbdevice = devs[0]
	return nil
}
Example #20
0
// StartBinaryUpgradeChecker checks for binary upgrades when the connection is
// up and on a schedule.
//
// This function runs in it's own goroutine.
func StartBinaryUpgradeChecker(diffsBaseURL string) {
	if !upgradeEnabled {
		lg.Infoln("binary upgrades are disabled using the command line flag")
		return
	}
	if VERSION == "" {
		lg.Warningln("VERSION not set, binary upgrades are disabled")
		return
	}
	_, err := version.NewVersion(VERSION)
	if err != nil {
		lg.Warningf("VERSION '%s' is not a valid semver version, binary upgrades are disabled: %v", VERSION, err)
		return
	}

	connectionEventListener := make(chan service.ConnectionHistory)
	uChecker, _ := NewUpdateChecker("binary")
	service.AddListener(connectionEventListener)
	for {
		select {
		// Update when the transport connection comes up
		case event := <-connectionEventListener:
			if event.IsUp() {
				uChecker.Activate()
				uChecker.UpdateNow()
			}

		// Update by request of the update checker
		case request := <-uChecker.RequestC:
			err := upgradeBinaryCheck(diffsBaseURL)
			if err != nil {
				lg.Errorln(err)
				request.ResponseC <- UpdateError
			} else {
				request.ResponseC <- UpdateSuccess
			}
		}
	}
}
Example #21
0
func importFromDevice(db *db.DB) error {

	if err := omronread.Open(); err != nil {
		return err
	}
	defer func() {
		if err := omronread.Close(); err != nil {
			lg.Errorln(err)
		}
	}()

	var all []omron.Entry

	{
		entries, err := omronread.Read(0)
		if err != nil {
			return err
		}
		all = append(all, entries...)

	}

	{
		entries, err := omronread.Read(1)
		if err != nil {
			return err
		}
		all = append(all, entries...)
	}
	sort.Sort(omron.ByTime(all))
	// data, err := json.MarshalIndent(all, "", "  ")
	// if err != nil {
	// lg.Fatal(err)
	// }
	return db.SaveEntries(all)

}
Example #22
0
func main() {
	runtime.LockOSThread()
	flag.Set("logtostderr", "true")
	lg.CopyStandardLogTo("INFO")
	lg.SetSrcHighlight("libomron")
	flag.Parse()

	bdb, err := bolt.Open("bpchart.db", 0600, &bolt.Options{Timeout: 1 * time.Second})
	if err != nil {
		lg.Fatal(err)
	}
	db := &db.DB{DB: bdb, BucketName: []byte(entriesBucketName)}

	var wg sync.WaitGroup

	wg.Add(1)
	go func() {
		lg.Fatal(httpServer(db))
		wg.Done()
	}()

	wg.Add(1)
	go func() {

		if FAKE {
			err = fakeImportFromDevice(db)
		} else {
			err = importFromDevice(db)
		}
		if err != nil {
			lg.Errorln(err)
		}
		wg.Done()
	}()

	wg.Wait()
}
Example #23
0
func exit() {
	lg.Infoln("alkasir is shutting down")
	atexitMu.Lock() // this lock should be kept, one shutdown should be enough for everyone.
	lg.Flush()
	if err := clientconfig.Write(); err != nil {
		lg.Errorf("could not save config file: %s", err.Error())
	}
	lg.V(9).Infoln("running atexit funcs")
	for _, f := range atexitFuncs {
		funcName := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
		lg.V(10).Infoln("Running at exit func", funcName)
		f()
		lg.V(10).Infoln("Finished at exit func", funcName)
	}
	atexitFuncs = atexitFuncs[:0]
	lg.V(9).Infoln("atexit funcs done")

	{
		lg.V(9).Infoln("stopping connectionmanager")
		done := make(chan bool)
		go func() {
			service.StopConnectionManager()
			done <- true
		}()
		select {
		case <-done:
		case <-time.After(10 * time.Second):
			lg.Errorln("services stop timed out")
		}
	}

	{
		done := make(chan bool)
		go func() {
			service.StopAll()
			done <- true
		}()
		select {
		case <-done:
			lg.V(9).Infoln("services stopped")
		case <-time.After(10 * time.Second):
			lg.Errorln("services stop timed out")
		}
	}

	{
		lg.V(9).Infoln("waiting for UI shutdown to finish")
		done := make(chan bool)
		go func() {
			uiRunning.Wait()
			done <- true
		}()
		select {
		case <-done:
		case <-time.After(10 * time.Second):
			lg.Errorln("timed out watning for ui shutdown")
		}
	}
	lg.Flush()
	lg.Infoln("alkasir shutdown complete")
	lg.Flush()
	time.Sleep(time.Millisecond * 1)
	os.Exit(0)
}
Example #24
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)
}
Example #25
0
func samplesAnalyzer() {
loop:
	for samples := range sampleAnalysisC {
		var (
			newTokenSample db.Sample
			clientSamples  = make(map[string]db.Sample, 0)
			centralSamples = make(map[string]db.Sample, 0)
		)

		// organize input data
		for _, s := range samples {
			switch s.Type {
			case "NewClientToken":
				if newTokenSample.Token != "" {
					lg.Error("got more than one newTokenSample, aborting")
					continue loop
				}
				newTokenSample = s
			case "HTTPHeader", "DNSQuery":
				switch s.Origin {
				case "Central":
					centralSamples[s.Type] = s
				case "Client":
					clientSamples[s.Type] = s
				}
			default:
				lg.Errorf("dont know how to handle %d %s, skipping", s.ID, s.Type)
			}
		}

		// validate that wanted data types are available
		if newTokenSample.Token == "" {
			lg.Errorln("No newTokenSample, aborting")
			continue loop
		}
		if !shared.AcceptedHost(newTokenSample.Host) {
			lg.Warningln("not accepted host id:", newTokenSample.ID, newTokenSample.Host)
			continue loop
		}
		for _, smap := range []map[string]db.Sample{clientSamples, centralSamples} {
			for _, stype := range []string{"HTTPHeader"} {
				if _, ok := smap[stype]; !ok {
					lg.Errorf("missing %s, cannot analyse", stype)
					continue loop
				}
			}
		}

		// parse data
		clientSample := clientSamples["HTTPHeader"]
		var clientHeader measure.HTTPHeaderResult
		centralSample := centralSamples["HTTPHeader"]
		var centralHeader measure.HTTPHeaderResult

		if err := json.Unmarshal(clientSample.Data, &clientHeader); err != nil {
			lg.Errorln(err)
			continue loop
		}
		if err := json.Unmarshal(centralSample.Data, &centralHeader); err != nil {
			lg.Error(err)
			continue loop
		}

		// score data
		score := scoreHTTPHeaders(clientHeader, centralHeader)
		lg.V(10).Infof("session:%s %s", newTokenSample.Token, score)

		if score.Score() >= 0.5 {
			lg.Infoln("publishing session", newTokenSample.Token)
			hostPublishC <- newTokenSample
		} else {
			lg.Infoln("not publishing session", newTokenSample.Token)
		}
	}
}
Example #26
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)

}
Example #27
0
func (h HTTPHeader) Measure() (Measurement, error) {
	timeout := h.Timeout
	if timeout == 0 {
		timeout = 45 * time.Second
	}

	resultchan := make(chan HTTPHeaderResult, 0)
	go func() {
		rr := &redirectRecorder{
			Transport: http.DefaultTransport.(*http.Transport),
		}
		client := http.Client{
			Timeout:   timeout,
			Transport: rr,
			CheckRedirect: func(req *http.Request, via []*http.Request) error {
				if len(via) >= 10 {
					return errors.New("stopped after 10 redirects")
				}
				return nil
			},
		}
		resp, err := client.Get(h.URL)
		if err != nil {
			resultchan <- HTTPHeaderResult{
				URL:   h.URL,
				Error: err.Error(),
			}
			return
		}
		defer func() {
			err := resp.Body.Close()
			if err != nil {
				// resp.Body should always have been closed at this point so an
				// error is expected.
				lg.V(20).Infoln(err)
			}
		}()
		respHeaders := make(map[string]string, 0)
		for k := range resp.Header {
			respHeaders[k] = resp.Header.Get(k)
		}
		if err := resp.Body.Close(); err != nil {
			lg.Errorln(err)
		}
		resultchan <- HTTPHeaderResult{
			URL:            h.URL,
			ResponseHeader: respHeaders,
			StatusCode:     resp.StatusCode,
			Redirects:      rr.Redirects,
		}
	}()
	select {
	case res := <-resultchan:
		return res, nil
	case <-time.After(timeout):
		return HTTPHeaderResult{
			URL:   h.URL,
			Error: "timeout: " + timeout.String(),
		}, nil
	}

}
Example #28
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())
			}
		}
	}
}
Example #29
0
func insertUpgrades([]string) error {
	if err := OpenDB(); err != nil {
		return err
	}

	files, err := findJSONFiles("diffs/")
	if err != nil {
		return err
	}
	var upgrades []db.UpgradeMeta

	for _, v := range files {
		lg.V(5).Infoln("reading", v)
		data, err := ioutil.ReadFile(v)
		if err != nil {
			return err
		}
		var cpr makepatch.CreatePatchResult
		err = json.Unmarshal(data, &cpr)
		if err != nil {
			return err
		}
		um, ok, err := sqlDB.GetUpgrade(db.GetUpgradeQuery{
			Artifact:        cpr.Artifact,
			Version:         cpr.NewVersion,
			AlsoUnpublished: true,
		})
		if err != nil {
			return err
		}
		if ok && um.Artifact == cpr.Artifact && um.Version == cpr.NewVersion {
			lgheader := cpr.Artifact + " " + cpr.NewVersion
			if um.ED25519Signature != cpr.ED25519Signature {
				lg.Warningf("%s signatures does not match!", lgheader)
			}
			if um.SHA256Sum != cpr.SHA256Sum {
				lg.Warningf("%s shasum does not match!", lgheader)
			}

			lg.Infof("%s is already imported, skipping", lgheader)
			continue
		}
		upgrades = append(upgrades, db.UpgradeMeta{
			Artifact:         cpr.Artifact,
			Version:          cpr.NewVersion,
			SHA256Sum:        cpr.SHA256Sum,
			ED25519Signature: cpr.ED25519Signature,
		})
	}
	{
		// NOTE: this will be removed later, a quick hack before other upgrades refactoring takes place
		uniqeUpgrades := make(map[string]db.UpgradeMeta, 0)
		for _, v := range upgrades {
			uniqeUpgrades[fmt.Sprintf("%s---%s", v.Artifact, v.Version)] = v
		}
		upgrades = upgrades[:0]
		for _, v := range uniqeUpgrades {
			upgrades = append(upgrades, v)
		}
	}

	fmt.Println(upgrades)
	err = sqlDB.InsertUpgrades(upgrades)
	if err != nil {
		lg.Errorln(err)
		return err
	}

	return nil
}
Example #30
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)
}