コード例 #1
0
ファイル: api_test.go プロジェクト: kyonetca/emp
func TestHandshake(t *testing.T) {
	config := initialize()

	var frame quibit.Frame
	var err error

	// Test Version
	frame = *objects.MakeFrame(objects.VERSION, objects.REQUEST, &config.LocalVersion)
	frame.Peer = "127.0.0.1:4444"

	config.RecvQueue <- frame

	frame = <-config.SendQueue

	if frame.Header.Command != objects.VERSION || frame.Header.Type != objects.REPLY {
		fmt.Println("Frame is not a proper reply to a version request: ", frame.Header)
		t.FailNow()
	}

	version := new(objects.Version)
	err = version.FromBytes(frame.Payload)
	if err != nil {
		fmt.Println("Error parsing version reply: ", err)
		t.FailNow()
	}

	// Test Peer
	frame = *objects.MakeFrame(objects.PEER, objects.REQUEST, &config.NodeList)
	frame.Peer = "127.0.0.1:4444"

	config.RecvQueue <- frame

	frame = <-config.SendQueue

	if frame.Header.Command != objects.PEER || frame.Header.Type != objects.REPLY || frame.Header.Length != 0 {
		fmt.Println("Frame is not a proper reply to a peer request: ", frame.Header)
		t.FailNow()
	}

	// Test Obj
	frame = *objects.MakeFrame(objects.OBJ, objects.REQUEST, &config.NodeList)
	frame.Peer = "127.0.0.1:4444"

	config.RecvQueue <- frame

	frame = <-config.SendQueue

	if frame.Header.Command != objects.OBJ || frame.Header.Type != objects.REPLY || frame.Header.Length != 0 {
		fmt.Println("Frame is not a proper reply to a peer request: ", frame.Header)
		t.FailNow()
	}

	cleanup(config)
}
コード例 #2
0
ファイル: localapi.go プロジェクト: dcposch/emp
func checkPubkey(config *api.ApiConfig, addrHash objects.Hash) []byte {

	// First check local DB
	detail, err := localdb.GetAddressDetail(addrHash)
	if err != nil {
		// If not in database, won't be able to decrypt anyway!
		return nil
	}
	if len(detail.Pubkey) > 0 {
		if db.Contains(addrHash) != db.PUBKEY {
			enc := new(objects.EncryptedPubkey)

			enc.IV, enc.Payload, _ = encryption.SymmetricEncrypt(detail.Address, string(detail.Pubkey))
			enc.AddrHash = objects.MakeHash(detail.Address)

			config.RecvQueue <- *objects.MakeFrame(objects.PUBKEY, objects.BROADCAST, enc)
		}
		return detail.Pubkey
	}

	// If not there, check local database
	if db.Contains(addrHash) == db.PUBKEY {
		enc := db.GetPubkey(config.Log, addrHash)

		pubkey := encryption.SymmetricDecrypt(enc.IV, detail.Address, enc.Payload)
		pubkey = pubkey[:65]

		// Check public Key
		x, y := encryption.UnmarshalPubkey(pubkey)
		if x == nil {
			config.Log <- "Decrypted Public Key Invalid"
			return nil
		}

		address2 := encryption.GetAddress(config.Log, x, y)
		if string(detail.Address) != string(address2) {
			config.Log <- "Decrypted Public Key doesn't match provided address!"
			return nil
		}

		detail.Pubkey = pubkey
		err := localdb.AddUpdateAddress(detail)
		if err != nil {
			config.Log <- "Error adding pubkey to local database!"
			return nil
		}

		return pubkey
	}

	// If not there, send a pubkey request
	config.RecvQueue <- *objects.MakeFrame(objects.PUBKEY_REQUEST, objects.BROADCAST, &addrHash)
	return nil
}
コード例 #3
0
ファイル: rpcmsg.go プロジェクト: dcposch/emp
func (service *EMPService) PurgeMessage(r *http.Request, args *[]byte, reply *NilParam) error {
	if len(*args) != 16 {
		return errors.New("Invalid Txid: Bad Length")
	}

	txidHash := objects.MakeHash(*args)

	if localdb.Contains(txidHash) <= localdb.SENDBOX {
		msg, err := localdb.GetMessageDetail(txidHash)
		if err != nil {
			return errors.New(fmt.Sprintf("Problem Retrieving Message: %s", err))
		}
		msg.MetaMessage.Purged = true
		localdb.AddUpdateMessage(msg, -1)

		// Send Purge Request
		purge := new(objects.Purge)
		purge.Txid = msg.Decrypted.Txid

		service.Config.RecvQueue <- *objects.MakeFrame(objects.PURGE, objects.BROADCAST, purge)

		return nil
	}

	return errors.New("Txid Not Found")
}
コード例 #4
0
ファイル: rpcmsg.go プロジェクト: dcposch/emp
func (service *EMPService) SendRawMsg(r *http.Request, args *RawMsg, reply *NilParam) error {
	if args == nil {
		return errors.New("Cannot work with nil message object!")
	}

	detail, err := localdb.GetAddressDetail(args.Message.AddrHash)
	if err != nil {
		return err
	}

	// Create New Message
	msg := new(objects.FullMessage)
	msg.Decrypted = nil
	msg.Encrypted = new(encryption.EncryptedMessage)
	msg.Encrypted.FromBytes(args.Message.Content.GetBytes())

	// Fill Out Meta Message (save timestamp)
	msg.MetaMessage.Purged = false

	msg.MetaMessage.TxidHash.FromBytes(args.Message.TxidHash.GetBytes())

	if args.Subscription {
		msg.MetaMessage.Sender = detail.String
		msg.MetaMessage.Recipient = ""
	} else {
		msg.MetaMessage.Sender = args.SendAddress
		msg.MetaMessage.Recipient = detail.String
	}

	err = localdb.AddUpdateMessage(msg, localdb.SENDBOX)
	if err != nil {
		return err
	}

	if args.Subscription {
		service.Config.RecvQueue <- *objects.MakeFrame(objects.PUB, objects.BROADCAST, &(args.Message))
	} else {
		service.Config.RecvQueue <- *objects.MakeFrame(objects.MSG, objects.BROADCAST, &(args.Message))
	}

	return nil
}
コード例 #5
0
ファイル: rpcfunc.go プロジェクト: dcposch/emp
func (service *EMPService) CreateAddress(r *http.Request, args *NilParam, reply *objects.AddressDetail) error {
	if !basicAuth(service.Config, r) {
		service.Config.Log <- fmt.Sprintf("Unauthorized RPC Request from: %s", r.RemoteAddr)
		return errors.New("Unauthorized")
	}

	// Create Address

	priv, x, y := encryption.CreateKey(service.Config.Log)
	reply.Privkey = priv
	if x == nil {
		return errors.New("Key Pair Generation Error")
	}

	reply.Pubkey = encryption.MarshalPubkey(x, y)

	reply.IsRegistered = true

	reply.Address = encryption.GetAddress(service.Config.Log, x, y)

	if reply.Address == nil {
		return errors.New("Could not create address, function returned nil.")
	}

	reply.String = encryption.AddressToString(reply.Address)

	// Add Address to Database
	err := localdb.AddUpdateAddress(reply)
	if err != nil {
		service.Config.Log <- fmt.Sprintf("Error Adding Address: ", err)
		return err
	}

	// Send Pubkey to Network
	encPub := new(objects.EncryptedPubkey)

	encPub.AddrHash = objects.MakeHash(reply.Address)

	encPub.IV, encPub.Payload, err = encryption.SymmetricEncrypt(reply.Address, string(reply.Pubkey))
	if err != nil {
		service.Config.Log <- fmt.Sprintf("Error Encrypting Pubkey: ", err)
		return nil
	}

	// Record Pubkey for Network
	service.Config.RecvQueue <- *objects.MakeFrame(objects.PUBKEY, objects.BROADCAST, encPub)
	return nil
}
コード例 #6
0
ファイル: api.go プロジェクト: dcposch/emp
// Starts a new TCP Server wth configuration specified in ApiConfig.
// Server will terminate cleanly only when data is sent to the Quit channel.
//
// See (struct ApiConfig) for details.
func Start(config *ApiConfig) {
	var err error
	var frame quibit.Frame

	defer quit(config)

	config.Log <- "Starting api..."

	// Start Database Services
	err = db.Initialize(config.Log, config.DbFile)
	defer db.Cleanup()
	if err != nil {
		config.Log <- fmt.Sprintf("Error initializing database: %s", err)
		config.Log <- "Quit"
		return
	}
	config.LocalVersion.Timestamp = time.Now().Round(time.Second)

	locVersion := objects.MakeFrame(objects.VERSION, objects.REQUEST, &config.LocalVersion)
	for str, _ := range config.NodeList.Nodes {
		locVersion.Peer = str
		config.SendQueue <- *locVersion
	}

	// Set Up Clocks
	second := time.Tick(2 * time.Second)
	minute := time.Tick(time.Minute)

	for {
		select {
		case frame = <-config.RecvQueue:
			config.Log <- fmt.Sprintf("Received %s frame...", CmdString(frame.Header.Command))
			switch frame.Header.Command {
			case objects.VERSION:
				version := new(objects.Version)
				err = version.FromBytes(frame.Payload)
				if err != nil {
					config.Log <- fmt.Sprintf("Error parsing version: %s", err)
				} else {
					fVERSION(config, frame, version)
				}
			case objects.PEER:
				nodeList := new(objects.NodeList)
				err = nodeList.FromBytes(frame.Payload)
				if err != nil {
					config.Log <- fmt.Sprintf("Error parsing peer list: %s", err)
				} else {
					fPEER(config, frame, nodeList)
				}
			case objects.OBJ:
				obj := new(objects.Obj)
				err = obj.FromBytes(frame.Payload)
				if err != nil {
					config.Log <- fmt.Sprintf("Error parsing obj list: %s", err)
				} else {
					fOBJ(config, frame, obj)
				}
			case objects.GETOBJ:
				getObj := new(objects.Hash)
				if len(frame.Payload) == 0 {
					break
				}
				err = getObj.FromBytes(frame.Payload)
				if err != nil {
					config.Log <- fmt.Sprintf("Error parsing getobj hash: %s", err)
				} else {
					fGETOBJ(config, frame, getObj)
				}
			case objects.PUBKEY_REQUEST:
				pubReq := new(objects.Hash)
				err = pubReq.FromBytes(frame.Payload)
				if err != nil {
					config.Log <- fmt.Sprintf("Error parsing pubkey request hash: %s", err)
				} else {
					fPUBKEY_REQUEST(config, frame, pubReq)
				}
			case objects.PUBKEY:
				pub := new(objects.EncryptedPubkey)
				err = pub.FromBytes(frame.Payload)
				if err != nil {
					config.Log <- fmt.Sprintf("Error parsing pubkey: %s", err)
				} else {
					fPUBKEY(config, frame, pub)
				}
			case objects.MSG:
				msg := new(objects.Message)
				err = msg.FromBytes(frame.Payload)
				if err != nil {
					config.Log <- fmt.Sprintf("Error parsing message: %s", err)
				} else {
					fMSG(config, frame, msg)
				}
			case objects.PUB:
				msg := new(objects.Message)
				err = msg.FromBytes(frame.Payload)
				if err != nil {
					config.Log <- fmt.Sprintf("Error parsing publication: %s", err)
				} else {
					fPUB(config, frame, msg)
				}
			case objects.PURGE:
				purge := new(objects.Purge)
				err = purge.FromBytes(frame.Payload)
				if err != nil {
					config.Log <- fmt.Sprintf("Error parsing purge: %s", err)
				} else {
					fPURGE(config, frame, purge)
				}
			case objects.CHECKTXID:
				chkTxid := new(objects.Hash)
				if len(frame.Payload) == 0 {
					break
				}
				err = chkTxid.FromBytes(frame.Payload)
				if err != nil {
					config.Log <- fmt.Sprintf("Error parsing checktxid hash: %s", err)
				} else {
					fCHECKTXID(config, frame, chkTxid)
				}
			default:
				config.Log <- fmt.Sprintf("Received invalid frame for command: %d", frame.Header.Command)
			}
		case <-config.Quit:
			fmt.Println()
			// Dump Nodes to File
			DumpNodes(config)
			return
		case <-second:
			// Reconnection Logic
			for key, node := range config.NodeList.Nodes {
				peer := quibit.GetPeer(key)
				if peer == nil || !peer.IsConnected() {
					quibit.KillPeer(key)
					if node.Attempts >= 3 {
						config.Log <- fmt.Sprintf("Max connection attempts reached for %s, disconnecting...", key)
						// Max Attempts Reached, disconnect
						delete(config.NodeList.Nodes, key)
					} else {
						config.Log <- fmt.Sprintf("Disconnected from peer %s, trying to reconnect...", key)
						peer = new(quibit.Peer)
						peer.IP = node.IP
						peer.Port = node.Port
						config.PeerQueue <- *peer
						runtime.Gosched()
						peer = nil
						node.Attempts++
						config.NodeList.Nodes[key] = node
						locVersion.Peer = key
						config.SendQueue <- *locVersion
					}
				}
			}

			if len(config.NodeList.Nodes) < 1 {
				config.Log <- "All connections lost, re-bootstrapping..."

				for i, str := range config.Bootstrap {
					if i >= bufLen {
						break
					}

					p := new(quibit.Peer)
					n := new(objects.Node)
					err := n.FromString(str)
					if err != nil {
						fmt.Println("Error Decoding Peer ", str, ": ", err)
						continue
					}

					p.IP = n.IP
					p.Port = n.Port
					config.PeerQueue <- *p
					runtime.Gosched()
					config.NodeList.Nodes[n.String()] = *n
				}

				for str, _ := range config.NodeList.Nodes {
					locVersion.Peer = str
					config.SendQueue <- *locVersion
				}
			}
		case <-minute:
			// Dump old messages
			err = db.SweepMessages(30 * 24 * time.Hour)
			if err != nil {
				config.Log <- fmt.Sprintf("Error Sweeping Messages: %s", err)
			}
		}
	}

	// Should NEVER get here!
	panic("Must've been a cosmic ray!")
}
コード例 #7
0
ファイル: localapi.go プロジェクト: dcposch/emp
// Handle Pubkey, Message, and Purge Registration
func register(config *api.ApiConfig) {
	var message objects.Message
	var txid [16]byte

	for {
		select {
		case pubHash := <-config.PubkeyRegister:

			// Check if pubkey is in database...
			pubkey := checkPubkey(config, pubHash)

			if pubkey == nil {
				break
			}

			outbox := localdb.GetBox(localdb.OUTBOX)
			for _, metamsg := range outbox {
				recvHash := objects.MakeHash([]byte(metamsg.Recipient))
				if string(pubHash.GetBytes()) == string(recvHash.GetBytes()) {
					// Send message and move to sendbox
					msg, err := localdb.GetMessageDetail(metamsg.TxidHash)
					if err != nil {
						config.Log <- err.Error()
						break
					}
					msg.Encrypted = encryption.Encrypt(config.Log, pubkey, string(msg.Decrypted.GetBytes()))
					msg.MetaMessage.Timestamp = time.Now().Round(time.Second)
					err = localdb.AddUpdateMessage(msg, localdb.SENDBOX)
					if err != nil {
						config.Log <- err.Error()
						break
					}

					sendMsg := new(objects.Message)
					sendMsg.Timestamp = msg.MetaMessage.Timestamp
					sendMsg.TxidHash = msg.MetaMessage.TxidHash
					sendMsg.AddrHash = recvHash
					sendMsg.Content = *msg.Encrypted

					config.RecvQueue <- *objects.MakeFrame(objects.MSG, objects.BROADCAST, sendMsg)
				}
			}

		case message = <-config.MessageRegister:
			// If address is registered, store message in inbox
			detail, err := localdb.GetAddressDetail(message.AddrHash)
			if err != nil {
				config.Log <- "Message address not in database..."
				break
			}
			if !detail.IsRegistered {
				config.Log <- "Message not for registered address..."
				break
			}

			config.Log <- "Registering new encrypted message..."

			msg := new(objects.FullMessage)
			msg.MetaMessage.TxidHash = message.TxidHash
			msg.MetaMessage.Timestamp = message.Timestamp
			msg.MetaMessage.Recipient = detail.String
			msg.Encrypted = &message.Content

			err = localdb.AddUpdateMessage(msg, localdb.INBOX)
			if err != nil {
				config.Log <- err.Error()
			}
		case message = <-config.PubRegister:
			// If address is registered, store message in inbox
			detail, err := localdb.GetAddressDetail(message.AddrHash)
			if err != nil {
				config.Log <- "Message address not in database..."
				break
			}
			if !detail.IsSubscribed {
				config.Log <- "Not Subscribed to Address..."
				break
			}

			config.Log <- "Registering new publication..."

			msg := new(objects.FullMessage)
			msg.MetaMessage.TxidHash = message.TxidHash
			msg.MetaMessage.Timestamp = message.Timestamp
			msg.MetaMessage.Sender = detail.String
			msg.MetaMessage.Recipient = "<Subscription Message>"
			msg.Encrypted = &message.Content

			msg.Decrypted = new(objects.DecryptedMessage)
			msg.Decrypted.FromBytes(encryption.DecryptPub(config.Log, detail.Pubkey, msg.Encrypted))

			err = localdb.AddUpdateMessage(msg, localdb.INBOX)
			if err != nil {
				config.Log <- err.Error()
			}
		case txid = <-config.PurgeRegister:
			// If Message in database, mark as purged
			detail, err := localdb.GetMessageDetail(objects.MakeHash(txid[:]))
			if err != nil {
				break
			}
			detail.MetaMessage.Purged = true
			err = localdb.AddUpdateMessage(detail, -1)
			if err != nil {
				config.Log <- fmt.Sprintf("Error registering purge: %s", err)
			}
		} // End select
	} // End for
} // End register
コード例 #8
0
ファイル: rpcmsg.go プロジェクト: dcposch/emp
func (service *EMPService) PublishMessage(r *http.Request, args *SendMsg, reply *SendResponse) error {
	if !basicAuth(service.Config, r) {
		service.Config.Log <- fmt.Sprintf("Unauthorized RPC Request from: %s", r.RemoteAddr)
		return errors.New("Unauthorized")
	}

	// Nil Check
	if len(args.Sender) == 0 || len(args.Plaintext) == 0 {
		return errors.New("All fields required.")
	}

	var err error

	// Get Addresses
	sendAddr := encryption.StringToAddress(args.Sender)
	if len(sendAddr) == 0 {
		return errors.New("Invalid sender address!")
	}

	sender, err := localdb.GetAddressDetail(objects.MakeHash(sendAddr))
	if err != nil {
		return errors.New(fmt.Sprintf("Error pulling send address from Database: %s", err))
	}
	if sender.Privkey == nil {
		return errors.New("Private Key Required to Publish Message")
	}

	// Create New Message
	msg := new(objects.FullMessage)
	msg.Decrypted = new(objects.DecryptedMessage)
	msg.Encrypted = nil

	txid := make([]byte, len(msg.Decrypted.Txid), cap(msg.Decrypted.Txid))

	// Fill out decrypted message
	n, err := rand.Read(txid)
	if n < len(msg.Decrypted.Txid[:]) || err != nil {
		return errors.New(fmt.Sprintf("Problem with random reader: %s", err))
	}
	copy(msg.Decrypted.Pubkey[:], sender.Pubkey)
	msg.Decrypted.Subject = args.Subject
	msg.Decrypted.MimeType = "text/plain"
	msg.Decrypted.Content = args.Plaintext
	msg.Decrypted.Length = uint32(len(msg.Decrypted.Content))

	// Fill Out Meta Message (save timestamp)
	msg.MetaMessage.Purged = false
	msg.MetaMessage.TxidHash = objects.MakeHash(txid)
	msg.MetaMessage.Sender = sender.String
	msg.MetaMessage.Recipient = "<Subscription Message>"

	// Get Signature
	priv := new(ecdsa.PrivateKey)
	priv.PublicKey.Curve = encryption.GetCurve()
	priv.D = new(big.Int)
	priv.D.SetBytes(sender.Privkey)

	sign := msg.Decrypted.GetBytes()
	sign = sign[:len(sign)-65]
	signHash := objects.MakeHash(sign)

	x, y, err := ecdsa.Sign(rand.Reader, priv, signHash.GetBytes())
	if err != nil {
		return err
	}

	copy(msg.Decrypted.Signature[:], encryption.MarshalPubkey(x, y))

	// Send message and add to sendbox...
	msg.Encrypted = encryption.EncryptPub(service.Config.Log, sender.Privkey, string(msg.Decrypted.GetBytes()))
	msg.MetaMessage.Timestamp = time.Now().Round(time.Second)

	// Now Add Txid
	copy(msg.Decrypted.Txid[:], txid)

	err = localdb.AddUpdateMessage(msg, localdb.SENDBOX)
	if err != nil {
		return err
	}

	sendMsg := new(objects.Message)
	sendMsg.TxidHash = msg.MetaMessage.TxidHash
	sendMsg.AddrHash = objects.MakeHash(sender.Address)
	sendMsg.Timestamp = msg.MetaMessage.Timestamp
	sendMsg.Content = *msg.Encrypted

	service.Config.RecvQueue <- *objects.MakeFrame(objects.PUB, objects.BROADCAST, sendMsg)

	reply.IsSent = true

	// Finish by setting msg's txid
	reply.TxidHash = msg.MetaMessage.TxidHash.GetBytes()
	return nil

}
コード例 #9
0
ファイル: rpcmsg.go プロジェクト: dcposch/emp
func (service *EMPService) OpenMessage(r *http.Request, args *[]byte, reply *objects.FullMessage) error {
	if !basicAuth(service.Config, r) {
		service.Config.Log <- fmt.Sprintf("Unauthorized RPC Request from: %s", r.RemoteAddr)
		return errors.New("Unauthorized")
	}

	var txidHash objects.Hash
	txidHash.FromBytes(*args)

	// Get Message from Database
	msg, err := localdb.GetMessageDetail(txidHash)
	if err != nil {
		return err
	}

	if msg.Encrypted == nil {
		*reply = *msg
		return nil
	}

	// If not decrypted, decrypt message and purge
	if msg.Decrypted == nil {
		recipient, err := localdb.GetAddressDetail(objects.MakeHash(encryption.StringToAddress(msg.MetaMessage.Recipient)))
		if err != nil {
			return err
		}

		if recipient.Privkey == nil {
			*reply = *msg
			return nil
		}

		// Decrypt Message
		decrypted := encryption.Decrypt(service.Config.Log, recipient.Privkey, msg.Encrypted)
		if len(decrypted) == 0 {
			*reply = *msg
			return nil
		}
		msg.Decrypted = new(objects.DecryptedMessage)
		msg.Decrypted.FromBytes(decrypted)

		// Update Sender

		x, y := encryption.UnmarshalPubkey(msg.Decrypted.Pubkey[:])
		address := encryption.GetAddress(service.Config.Log, x, y)
		addrStr := encryption.AddressToString(address)
		addrHash := objects.MakeHash(address)

		detail, _ := localdb.GetAddressDetail(addrHash)
		if detail == nil {
			detail = new(objects.AddressDetail)
		}
		detail.Address = address
		detail.String = addrStr
		detail.Pubkey = msg.Decrypted.Pubkey[:]

		localdb.AddUpdateAddress(detail)
		msg.MetaMessage.Sender = detail.String

		// Send Purge Request
		purge := new(objects.Purge)
		purge.Txid = msg.Decrypted.Txid

		service.Config.RecvQueue <- *objects.MakeFrame(objects.PURGE, objects.BROADCAST, purge)
		msg.MetaMessage.Purged = true

		localdb.AddUpdateMessage(msg, localdb.Contains(msg.MetaMessage.TxidHash))
	} else {
		if msg.MetaMessage.Purged == false && localdb.Contains(txidHash) == localdb.INBOX {
			msg.MetaMessage.Purged = true
			localdb.AddUpdateMessage(msg, localdb.Contains(msg.MetaMessage.TxidHash))
		}
	}

	*reply = *msg
	return nil
}