Beispiel #1
0
func (ms MessageServer) notifyWatch() {
	var lastNotify, lastMessage int64
	notifyTick := time.Tick(time.Duration(ms.NotifyDuration) * time.Second)
	fetchTick := time.Tick(time.Duration(ms.FetchDuration) * time.Second)
	expireTick := time.Tick(time.Duration(ms.ExpireDuration) * time.Second)
	var statTick <-chan time.Time
	if ms.Stat {
		// show statistics once a minute
		statTick = time.Tick(60 * time.Second)
	}
	for {
		select {
		case <-notifyTick:
			log.Debugs("Check notification.\n")
			if lastNotify < lastMessage { // both are zero when started
				log.Debugs("Notify run started.\n")
				lastNotify = CurrentTime()
				ms.NotifyPeers()
			}
		case <-fetchTick:
			log.Debugs("Fetch run started.\n")
			ms.FetchRun()
		case <-expireTick:
			log.Debugs("Expire run started.\n")
			ms.DB.ExpireFromIndex()
		case <-statTick:
			stat.Input <- stat.Show
		case <-ms.notifyChan:
			log.Debugs("Notification reason\n")
			lastMessage = CurrentTime()
		}
	}
}
Beispiel #2
0
// LoadPeers from file.
func (ms MessageServer) LoadPeers() {
	var prePeerlist PeerListEncoded
	var myPeerURLs []string
	myPeers := make(PeerList)
	peersEncoded, err := ioutil.ReadFile(ms.PeerFile)
	if err != nil {
		example := make(PeerListEncoded, 1)
		example[0].PubKey = "Example ed25519 public key encoded in base58"
		example[0].URL = exampleURL
		dat, _ := json.MarshalIndent(example, "", "    ")
		_ = dat
		err := ioutil.WriteFile(ms.PeerFile, dat, 0600)
		if err != nil {
			log.Errorf("Could not write peerfile: %s\n", err)
			return
		}
		log.Debugs("Example peerfile written\n")
		return
	}
	err = json.Unmarshal(peersEncoded, &prePeerlist)
	if err != nil {
		log.Errorf("Could not read peerfile: %s\n", err)
		return
	}
	if ms.AddToPeer && !ms.HubOnly {
		myPeerURLs = append(myPeerURLs, ms.URL)
	}
	for _, p := range prePeerlist {
		if p.URL != exampleURL {
			var tkey [ed25519.PublicKeySize]byte
			t := utils.B58decode(p.PubKey)
			copy(tkey[:], t)
			if *ms.TokenPubKey != tkey || debug {
				myPeers[tkey] = Peer{
					URL:    p.URL,
					PubKey: tkey,
				}
				if !p.IsHub {
					myPeerURLs = append(myPeerURLs, p.URL)
				}
				// Create Peer Index File
				ms.DB.TouchPeer(&tkey)
			}
		}
	}
	defer ms.setPeerURLs(myPeerURLs)
	systemPeersMutex.Lock()
	defer systemPeersMutex.Unlock()
	systemPeers = myPeers
	log.Debugs("Peers loaded\n")
}
Beispiel #3
0
// FetchPost fetches a post from a peer and adds it.
func (ms MessageServer) FetchPost(url, auth string, msgID [message.MessageIDSize]byte, expireRequest uint64) error {
	// Fetch the post
	proto := repproto.New(ms.SocksProxy, "")
	data, err := proto.GetSpecificAuth(url, auth, msgID[:])
	// data, err := proto.GetSpecific(url, msgID[:])
	if err != nil {
		return err
	}
	// Verify and use it
	signheader, err := message.Base64Message(data).GetSignHeader()
	if err != nil {
		log.Debugf("Bad fetch:GetSignHeader: %s\n", err)
		return err
	}
	details, err := message.VerifySignature(*signheader, ms.MinHashCashBits)
	if err != nil {
		log.Debugf("Bad fetch:VerifySignature: %s\n", err)
		return err
	}
	constantRecipientPub, MessageID, err := deferVerify(data)
	if err != nil {
		log.Debugf("Bad fetch:deferVerify: %s\n", err)
		return err
	}
	if *MessageID != details.MsgID {
		log.Debugs("Bad fetch:MessageID\n")
		return ErrBadMessageID
	}
	msgStruct := &structs.MessageStruct{
		MessageID:              *MessageID,
		ReceiverConstantPubKey: *constantRecipientPub,
		SignerPub:              details.PublicKey,
		OneTime:                false,
		Sync:                   false,
		Hidden:                 false,
		ExpireRequest:          expireRequest,
	}
	if message.KeyIsSync(constantRecipientPub) {
		msgStruct.Sync = true
	}
	if message.KeyIsHidden(constantRecipientPub) {
		msgStruct.Hidden = true
	}

	sigStruct := &structs.SignerStruct{
		PublicKey: details.PublicKey,
		Nonce:     details.HashCashNonce,
		Bits:      details.HashCashBits,
	}
	sigStruct.MaxMessagesPosted, sigStruct.MaxMessagesRetained, sigStruct.ExpireTarget = ms.calcLimits(details.HashCashBits)
	return ms.DB.Put(msgStruct, sigStruct, data)
}
Beispiel #4
0
func getPeers(force bool) error {
	log.Debugf("Peer update called. Last: %d\n", GlobalConfigVar.PeerUpdate)
	if GlobalConfigVar.PeerUpdate == 0 || GlobalConfigVar.PeerUpdate < (time.Now().Unix()-PeerUpdateDuration) {
		log.Debugs("Peer update forced. Prevent by running -peerlist.\n")
		force = true
	}
	if force {
		log.Debugs("Updating peers.\n")
		defer log.Debugs("Peer update done.\n")
		GlobalConfigVar.PeerUpdate = time.Now().Unix()
		server := OptionsVar.Server
		if server == "" && GlobalConfigVar.PasteServers != nil && len(GlobalConfigVar.PasteServers) > 0 { // no server defined, we select one
			servercount := len(GlobalConfigVar.PasteServers)
			rand.Seed(time.Now().UnixNano())
			pos := rand.Int() % servercount
			server = GlobalConfigVar.PasteServers[pos]
		}
		if server == "" {
			server = GlobalConfigVar.BootStrapPeer
		}
		if server == "" {
			return ErrNoPeers
		}
		proto := repproto.New(OptionsVar.Socksserver, OptionsVar.Server, GlobalConfigVar.PasteServers...)
		serverInfo, err := proto.ID(server)
		if err != nil {
			return ErrNoPeers
		}
		if serverInfo.Peers != nil && len(serverInfo.Peers) > 0 {
			GlobalConfigVar.PasteServers = serverInfo.Peers
			GlobalConfigVar.MinHashCash = serverInfo.MinHashCashBits
			err := WriteConfigFile(GlobalConfigVar)
			if err != nil {
				log.Errorf("Error writing config-file: %s\n", err)
			}
		}
	}
	return nil
}
Beispiel #5
0
// Fetch returns a single message.
func (ms MessageServer) Fetch(w http.ResponseWriter, r *http.Request) {
	var messageID *[message.MessageIDSize]byte
	w.Header().Set("Content-Type", "text/plain; charset=us-ascii")
	getValues := r.URL.Query()
	if getValues != nil {
		if v, ok := getValues["messageid"]; ok {
			t := utils.B58decode(v[0])
			if len(t) < message.MessageIDSize || len(t) > message.MessageIDSize {
				io.WriteString(w, "ERROR: Bad parameter\n")
				return
			}
			messageID = new([message.MessageIDSize]byte)
			copy(messageID[:], t)
		}
		if ms.HubOnly {
			if v, ok := getValues["auth"]; ok {
				err := ms.AuthenticatePeer(v[0])
				if err != nil {
					io.WriteString(w, fmt.Sprintf("Error: %s", err))
					return
				}
			} else {
				io.WriteString(w, "ERROR: Missing param\n")
				return
			}
		}
	}
	if messageID == nil {
		io.WriteString(w, "ERROR: Missing parameter\n")
		return
	}
	data, err := ms.DB.Fetch(messageID)
	if err != nil {
		log.Debugf("Fetch: %s\n", err)
		io.WriteString(w, "ERROR: No data")
		return
	}
	io.WriteString(w, "SUCCESS: Data follows\n")
	_, err = w.Write(data)
	if err != nil {
		log.Debugf("Write: %s\n", err)
		return
	}
	log.Debugs("Fetch OK\n")
	if ms.Stat {
		stat.Input <- stat.Fetch
	}
	return
}
Beispiel #6
0
func (store Store) expireSigners() {
	//s.signers = fileback.NewRoundRobin(dir+signerDir, structs.SignerStructSize, 10, ' ', []byte("\n"), workers)       // We keep signer history, last 10 entries
	now := time.Now().Unix()
	indices := store.signers.Indices()
	if indices == nil {
		log.Debugs("ExpireFS: No signers\n")
		return
	}
	for _, signer := range indices {
		last := store.signers.Index(signer).LastChange(0)
		if last != 0 && last < now-int64(FSExpire) {
			store.signers.Index(signer).Truncate() // We don't delete for real, otherwise the signer would become reusable.
			log.Debugf("ExpireFS: Signer truncated %x\n", signer)
		} else {
			log.Debugf("ExpireFS: Signer remains %x\n", signer)
		}
	}
}
Beispiel #7
0
func (store Store) expireKeyIndices() {
	//s.keyindex = fileback.NewRolling(dir+keyindexDir, structs.MessageStructSize, 2048, ' ', []byte("\n"), workers)    // Maximum 2048 entries per file
	now := time.Now().Unix()
	indices := store.keyindex.Indices()
	if indices == nil {
		log.Debugs("ExpireFS: No Key Indices\n")
		return
	}
	for _, keylist := range indices {
		entry := store.signers.Index(keylist)
		last := entry.LastChange(0)
		if last != 0 && last < now-int64(FSExpire) {
			// go forward
			lastEntry := entry.Entries() - 1
			if lastEntry >= 0 {
				last := entry.LastChange(lastEntry)
				if last < now-int64(FSExpire) {
					log.Debugf("ExpireFS: Key Index complete delete %x\n", keylist)
					entry.Delete() // Key lists are deleted
				} else {
					maxEntries := entry.MaxEntries()
					deleteBefore := int64(-1)
				LastLoop:
					for pos := lastEntry; pos > 0; pos = pos - maxEntries { // Search the first entry that has expired
						last := entry.LastChange(pos)
						if last != 0 && last < now-int64(FSExpire) {
							break LastLoop
						}
						deleteBefore = pos - 1 // This will actually skip the last expired object
					}
					if deleteBefore >= 0 {
						log.Debugf("ExpireFS: Key Index delete before %d %x\n", deleteBefore, keylist)
						entry.DeleteBefore(deleteBefore)
					} else {
						log.Debugf("ExpireFS: Key Index no delete match %x\n", keylist)
					}
				}
			}
		} else {
			log.Debugf("ExpireFS: Key Index remains %x\n", keylist)
		}
	}
}
Beispiel #8
0
// AuthenticatePeer verifies an existing authStr and matches it to the known peers.
func (ms MessageServer) AuthenticatePeer(authStr string) error {
	var counterSig [keyproof.ProofTokenSignedSize]byte
	var auth []byte
	if len(authStr) > keyproof.ProofTokenSignedMax {
		return fmt.Errorf("Bad param")
	}
	auth = utils.B58decode(authStr)
	if len(auth) > keyproof.ProofTokenSignedSize {
		return fmt.Errorf("Bad param")
	}
	copy(counterSig[:], auth)
	ok, timestamp := keyproof.VerifyCounterSig(&counterSig, ms.TokenPubKey)
	if !ok {
		log.Debugs("List:Auth no verify\n")
		return fmt.Errorf("Authentication failed: No match")
	}
	now := CurrentTime()
	if enforceTimeOuts && (timestamp < now-ms.MaxAuthTokenAge-ms.MaxTimeSkew || timestamp > now+ms.MaxAuthTokenAge+ms.MaxTimeSkew) {
		return fmt.Errorf("Authentication failed: Timeout")
	}
	return nil
}
Beispiel #9
0
// ProcessPost verifies and adds a post to the database.
func (ms MessageServer) ProcessPost(postdata io.ReadCloser, oneTime bool, expireRequest uint64) string {
	data, err := utils.MaxRead(ms.MaxPostSize, postdata)
	if err != nil {
		return "ERROR: Message too big\n"
	}
	if len(data) < ms.MinPostSize {
		return "ERROR: Message too small\n"
	}
	signheader, err := message.Base64Message(data).GetSignHeader()
	if err != nil {
		log.Debugf("Post:GetSignHeader: %s\n", err)
		return "ERROR: Sign Header\n"
	}
	details, err := message.VerifySignature(*signheader, ms.MinHashCashBits)
	if err != nil {
		log.Debugf("Post:VerifySignature: %s\n", err)
		return "ERROR: HashCash\n"
	}
	constantRecipientPub, MessageID, err := deferVerify(data)
	if err != nil {
		log.Debugf("Post:deferVerify: %s\n", err)
		return "ERROR: Verify\n"
	}
	if *MessageID != details.MsgID {
		log.Debugs("Post:MessageID\n")
		return "ERROR: MessageID\n"
	}
	msgStruct := &structs.MessageStruct{
		MessageID:              *MessageID,
		ReceiverConstantPubKey: *constantRecipientPub,
		SignerPub:              details.PublicKey,
		OneTime:                oneTime,
		Sync:                   false,
		Hidden:                 false,
		ExpireRequest:          expireRequest,
	}
	if !oneTime {
		if message.KeyIsSync(constantRecipientPub) {
			msgStruct.Sync = true
		}
	} else {
		msgStruct.Sync = false
	}
	if message.KeyIsHidden(constantRecipientPub) {
		msgStruct.Hidden = true
	}

	sigStruct := &structs.SignerStruct{
		PublicKey: details.PublicKey,
		Nonce:     details.HashCashNonce,
		Bits:      details.HashCashBits,
	}
	sigStruct.MaxMessagesPosted, sigStruct.MaxMessagesRetained, sigStruct.ExpireTarget = ms.calcLimits(details.HashCashBits)
	_, _ = msgStruct, sigStruct
	ms.RandomSleep()
	// err = ms.DB.Put(msgStruct, sigStruct, data)
	err = ms.DB.PutNotify(msgStruct, sigStruct, data, ms.notifyChan)
	ms.RandomSleep()
	if err != nil {
		log.Debugf("Post:MessageDB: %s\n", err)
		return fmt.Sprintf("ERROR: %s\n", err)
	}
	log.Debugf("Post:Added: %x\n", MessageID[:12])
	if ms.Stat {
		stat.Input <- stat.Post
	}
	return "SUCCESS: Connection close\n"
}
Beispiel #10
0
// GetKeyIndex returns the index for a key.
func (ms MessageServer) GetKeyIndex(w http.ResponseWriter, r *http.Request) {
	var pubKey *message.Curve25519Key
	var auth []byte
	start := int64(0)
	count := int64(10)
	w.Header().Set("Content-Type", "text/plain; charset=us-ascii")
	getValues := r.URL.Query()
	if getValues != nil {
		if v, ok := getValues["start"]; ok {
			t, err := strconv.Atoi(v[0])
			if err == nil {
				start = int64(t)
			}
		}
		if v, ok := getValues["count"]; ok {
			t, err := strconv.Atoi(v[0])
			if err == nil {
				count = int64(t)
				if count > ms.MaxIndexKey {
					count = ms.MaxIndexKey
				}
			}
		}
		if v, ok := getValues["key"]; ok {
			if len(v[0]) > message.Curve25519KeySize*10 {
				io.WriteString(w, "ERROR: Bad param\n")
				return
			}
			t := utils.B58decode(v[0])
			if len(t) != message.Curve25519KeySize {
				io.WriteString(w, "ERROR: Bad param\n")
				return
			}
			pubKey = new(message.Curve25519Key)
			copy(pubKey[:], t)
			if v, ok := getValues["auth"]; ok {
				if len(v[0]) > keyauth.AnswerSize*10 {
					io.WriteString(w, "ERROR: Bad param\n")
					return
				}
				auth = utils.B58decode(v[0])
				if len(auth) != keyauth.AnswerSize {
					io.WriteString(w, "ERROR: Bad param\n")
					return
				}
			}
		} else {
			io.WriteString(w, "ERROR: Missing param\n")
			return
		}
	} else {
		io.WriteString(w, "ERROR: Missing param\n")
		return
	}
	if pubKey == nil {
		io.WriteString(w, "ERROR: Missing param\n")
		return
	}
	if message.KeyIsHidden(pubKey) {
		if auth == nil {
			log.Debugs("List:Auth missing\n")
			io.WriteString(w, "ERROR: Authentication required\n")
			return
		}
		answer := [keyauth.AnswerSize]byte{}
		copy(answer[:], auth)
		now := uint64(time.Now().Unix() + ms.TimeSkew)
		if !keyauth.VerifyTime(&answer, now, ms.TimeGrace) {
			log.Debugs("List:Auth timeout\n")
			io.WriteString(w, "ERROR: Authentication failed: Timeout\n")
			return
		}
		privK := [32]byte(*ms.authPrivKey)
		testK := [32]byte(*pubKey)
		if !keyauth.Verify(&answer, &privK, &testK) {
			log.Debugs("List:Auth no verify\n")
			io.WriteString(w, "ERROR: Authentication failed: No Match\n")
			return
		}
	}
	messages, found, err := ms.DB.GetIndex(pubKey, start, count)
	if err != nil && err != fileback.ErrNoMore {
		log.Debugf("List:GetIndex: %s\n", err)
		log.Debugf("List:GetIndex: Key %x\n", pubKey)
		io.WriteString(w, "ERROR: List failed\n")
		return
	}
	io.WriteString(w, "SUCCESS: Data follows\n")
	for _, msg := range messages {
		io.WriteString(w, "IDX: "+strings.Trim(string(msg), " \t\n\r")+"\n")
	}
	if int64(found) < count {
		io.WriteString(w, "CMD: Exceeded\n")
	} else {
		io.WriteString(w, "CMD: Continue\n")
	}
}