// Get Encrypted Public Key from database. func GetPubkey(log chan string, addrHash objects.Hash) *objects.EncryptedPubkey { mutex.Lock() defer mutex.Unlock() hash := addrHash.GetBytes() if hashList == nil || dbConn == nil { return nil } if hashList[string(hash)] != PUBKEY { return nil } for s, err := dbConn.Query("SELECT payload FROM pubkey WHERE hash=?", hash); err == nil; err = s.Next() { var payload []byte s.Scan(&payload) // Assigns 1st column to rowid, the rest to row pub := new(objects.EncryptedPubkey) pub.AddrHash = addrHash copy(pub.IV[:], payload[:16]) pub.Payload = payload[16:] return pub } // Not Found return nil }
// Add Purge Token to database, and remove corresponding message if necessary. func AddPurge(log chan string, p objects.Purge) error { mutex.Lock() defer mutex.Unlock() txid := p.GetBytes() hashArr := sha512.Sum384(txid) hash := hashArr[:] if hashList == nil || dbConn == nil { return DBError(EUNINIT) } hashObj := new(objects.Hash) hashObj.FromBytes(hash) if Contains(*hashObj) == PURGE { return nil } err := dbConn.Exec("INSERT INTO purge VALUES (?, ?)", hash, txid) if err != nil { log <- fmt.Sprintf("Error inserting purge into db... %s", err) return err } Add(*hashObj, PURGE) return nil }
// Get basic message from database. func GetMessage(log chan string, txidHash objects.Hash) *objects.Message { mutex.Lock() defer mutex.Unlock() hash := txidHash.GetBytes() if hashList == nil || dbConn == nil { return nil } if hashList[string(hash)] != MSG && hashList[string(hash)] != PUB { return nil } msg := new(objects.Message) for s, err := dbConn.Query("SELECT * FROM msg WHERE hash=?", hash); err == nil; err = s.Next() { var timestamp int64 encrypted := make([]byte, 0, 0) txidhash := make([]byte, 0, 0) addrhash := make([]byte, 0, 0) s.Scan(&txidhash, &addrhash, ×tamp, &encrypted) msg.TxidHash.FromBytes(txidhash) msg.AddrHash.FromBytes(addrhash) msg.Timestamp = time.Unix(timestamp, 0) msg.Content.FromBytes(encrypted) return msg } // Not Found return nil }
// Remove any object from the database and hash list. func RemoveHash(log chan string, hashObj objects.Hash) error { mutex.Lock() defer mutex.Unlock() hash := hashObj.GetBytes() if hashList == nil || dbConn == nil { return DBError(EUNINIT) } var sql string switch Contains(hashObj) { case PUBKEY: sql = "DELETE FROM pubkey WHERE hash=?" case MSG: sql = "DELETE FROM msg WHERE hash=?" case PURGE: sql = "DELETE FROM purge WHERE hash=?" default: return nil } err := dbConn.Exec(sql, hash) if err != nil { log <- fmt.Sprintf("Error deleting hash from db... %s", err) return nil } Delete(hashObj) return nil }
func DeleteAddress(addrHash *objects.Hash) error { localMutex.Lock() defer localMutex.Unlock() if Contains(*addrHash) > ADDRESS { return errors.New("Error Deleting Message: Not Found!") } return LocalDB.Exec("DELETE FROM addressbook WHERE hash=?", addrHash.GetBytes()) }
func DeleteMessage(txidHash *objects.Hash) error { localMutex.Lock() defer localMutex.Unlock() if Contains(*txidHash) > SENDBOX { return errors.New("Error Deleting Message: Not Found!") } return LocalDB.Exec("DELETE FROM msg WHERE txid_hash=?", txidHash.GetBytes()) }
// Get type of object in Hash List func Contains(hashObj objects.Hash) int { hash := string(hashObj.GetBytes()) if hashList != nil { hashType, ok := hashList[hash] if ok { return hashType } else { return NOTFOUND } } return NOTFOUND }
// List of all hashes in the hash list. func ObjList() *objects.Obj { if hashList == nil { return nil } ret := new(objects.Obj) ret.HashList = make([]objects.Hash, 0, 0) hash := new(objects.Hash) for key, _ := range hashList { hash.FromBytes([]byte(key)) ret.HashList = append(ret.HashList, *hash) } return ret }
func (service *EMPService) GetEncrypted(r *http.Request, args *[]byte, reply *encryption.EncryptedMessage) 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 } *reply = *msg.Encrypted return nil }
func GetMessageDetail(txidHash objects.Hash) (*objects.FullMessage, error) { localMutex.Lock() defer localMutex.Unlock() if Contains(txidHash) > SENDBOX { return nil, errors.New("Message not found!") } ret := new(objects.FullMessage) ret.Encrypted = new(encryption.EncryptedMessage) ret.Decrypted = new(objects.DecryptedMessage) s, err := LocalDB.Query("SELECT * FROM msg WHERE txid_hash=?", txidHash.GetBytes()) if err == nil { recipient := make([]byte, 0, 0) sender := make([]byte, 0, 0) encrypted := make([]byte, 0, 0) decrypted := make([]byte, 0, 0) txidHash := make([]byte, 0, 0) var timestamp int64 var purged bool var box int s.Scan(&txidHash, &recipient, ×tamp, &box, &encrypted, &decrypted, &purged, &sender) ret.MetaMessage.TxidHash.FromBytes(txidHash) ret.MetaMessage.Recipient = encryption.AddressToString(recipient) ret.MetaMessage.Sender = encryption.AddressToString(sender) ret.MetaMessage.Timestamp = time.Unix(timestamp, 0) ret.MetaMessage.Purged = purged ret.Encrypted.FromBytes(encrypted) if len(decrypted) > 0 { ret.Decrypted.FromBytes(decrypted) } else { ret.Decrypted = nil } return ret, nil } return nil, err }
func DeleteObject(obj objects.Hash) error { var err error switch Contains(obj) { case INBOX: fallthrough case SENDBOX: fallthrough case OUTBOX: err = LocalDB.Exec("DELETE FROM msg WHERE txid_hash=?", obj.GetBytes()) case ADDRESS: err = LocalDB.Exec("DELETE FROM addressbook WHERE hash=?", obj.GetBytes()) default: err = errors.New("Hash not found!") } if err == nil { Del(obj) } return err }
// Get purge token from the database. func GetPurge(log chan string, txidHash objects.Hash) *objects.Purge { mutex.Lock() defer mutex.Unlock() hash := txidHash.GetBytes() if hashList == nil || dbConn == nil { return nil } if hashList[string(hash)] != PURGE { return nil } for s, err := dbConn.Query("SELECT txid FROM purge WHERE hash=?", hash); err == nil; err = s.Next() { var txid []byte s.Scan(&txid) // Assigns 1st column to rowid, the rest to row p := new(objects.Purge) p.FromBytes(txid) return p } // Not Found return nil }
func (service *EMPService) DeleteMessage(r *http.Request, args *[]byte, reply *NilParam) error { txidHash := new(objects.Hash) txidHash.FromBytes(*args) return localdb.DeleteMessage(txidHash) }
// Delete hash from Hash List func Del(hashObj objects.Hash) { hash := string(hashObj.GetBytes()) if hashList != nil { delete(hashList, hash) } }
// Add to global Hash List. func Add(hashObj objects.Hash, hashType int) { hash := string(hashObj.GetBytes()) if hashList != nil { hashList[hash] = hashType } }
func GetAddressDetail(addrHash objects.Hash) (*objects.AddressDetail, error) { localMutex.Lock() defer localMutex.Unlock() if Contains(addrHash) != ADDRESS { return nil, errors.New("Address not found!") } ret := new(objects.AddressDetail) s, err := LocalDB.Query("SELECT address, registered, pubkey, privkey, label, subscribed, encprivkey FROM addressbook WHERE hash=?", addrHash.GetBytes()) if err == nil { s.Scan(&ret.Address, &ret.IsRegistered, &ret.Pubkey, &ret.Privkey, &ret.Label, &ret.IsSubscribed, &ret.EncPrivkey) ret.String = encryption.AddressToString(ret.Address) return ret, nil } return nil, err }
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 }
// 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!") }