586 lines
23 KiB
Go
586 lines
23 KiB
Go
|
|
||
|
// myChatKeys provides functions to manage a user's chat keys
|
||
|
// New keys are created after a set duration has passed
|
||
|
// Old keys are deleted after the user has downloaded all of the messages during the period when they were used
|
||
|
|
||
|
package myChatKeys
|
||
|
|
||
|
import "seekia/internal/cryptography/kyber"
|
||
|
import "seekia/internal/cryptography/nacl"
|
||
|
import "seekia/internal/encoding"
|
||
|
import "seekia/internal/helpers"
|
||
|
import "seekia/internal/identity"
|
||
|
import "seekia/internal/logger"
|
||
|
import "seekia/internal/messaging/readMessages"
|
||
|
import "seekia/internal/myDatastores/myMap"
|
||
|
import "seekia/internal/myDatastores/myMapList"
|
||
|
import "seekia/internal/myIdentity"
|
||
|
|
||
|
import "sync"
|
||
|
import "time"
|
||
|
import "strings"
|
||
|
import "errors"
|
||
|
|
||
|
//TODO: Add pruning function to get rid of old keys
|
||
|
|
||
|
// This mutex will be locked whenever we update the chat keys maplist
|
||
|
var updatingMyChatKeysMutex sync.Mutex
|
||
|
|
||
|
// This mutex will be locked whenever we update the chatKeysLatestUpdateTime map object
|
||
|
var updatingMyChatKeysLatestUpdateTimeMutex sync.Mutex
|
||
|
|
||
|
var myChatKeysMapListDatastore *myMapList.MyMapList
|
||
|
|
||
|
// Map Structure: Identity Hash + "@" + Network Type -> Latest update unix time
|
||
|
var myChatKeysLatestUpdateTimeMapDatastore *myMap.MyMap
|
||
|
|
||
|
// Map Structure: Identity Hash + "@" + Network Type -> Nacl Key + "+" + Kyber Key
|
||
|
var myNewestBroadcastPublicChatKeysMapDatastore *myMap.MyMap
|
||
|
|
||
|
|
||
|
// This function must be called whenever an app user signs in
|
||
|
func InitializeMyChatKeysDatastores()error{
|
||
|
|
||
|
updatingMyChatKeysMutex.Lock()
|
||
|
defer updatingMyChatKeysMutex.Unlock()
|
||
|
|
||
|
updatingMyChatKeysLatestUpdateTimeMutex.Lock()
|
||
|
defer updatingMyChatKeysLatestUpdateTimeMutex.Unlock()
|
||
|
|
||
|
newMyChatKeysLatestUpdateTimeMapDatastore, err := myMap.CreateNewMap("MyChatKeysLatestUpdateTime")
|
||
|
if (err != nil) { return err }
|
||
|
|
||
|
newMyChatKeysMapListDatastore, err := myMapList.CreateNewMapList("MyChatKeys")
|
||
|
if (err != nil) { return err }
|
||
|
|
||
|
newMyNewestBroadcastPublicChatKeysMapDatastore, err := myMap.CreateNewMap("MyNewestBroadcastPublicChatKeys")
|
||
|
if (err != nil) { return err }
|
||
|
|
||
|
myChatKeysLatestUpdateTimeMapDatastore = newMyChatKeysLatestUpdateTimeMapDatastore
|
||
|
|
||
|
myChatKeysMapListDatastore = newMyChatKeysMapListDatastore
|
||
|
|
||
|
myNewestBroadcastPublicChatKeysMapDatastore = newMyNewestBroadcastPublicChatKeysMapDatastore
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// This function provides the decryption keys for a particular identity hash
|
||
|
|
||
|
//Outputs:
|
||
|
// -bool: My identity found
|
||
|
// -bool: Any chat keys found (will be false if user has never broadcasted their profile)
|
||
|
// -[]ChatKeySet: Chat keys list
|
||
|
// -error
|
||
|
func GetMyChatDecryptionKeySetsList(myIdentityHash [16]byte, networkType byte)(bool, bool, []readMessages.ChatKeySet, error){
|
||
|
|
||
|
isMine, myIdentityType, err := myIdentity.CheckIfIdentityHashIsMine(myIdentityHash)
|
||
|
if (err != nil) { return false, false, nil, err }
|
||
|
if (isMine == false) {
|
||
|
return false, false, nil, nil
|
||
|
}
|
||
|
|
||
|
if (myIdentityType != "Mate" && myIdentityType != "Moderator"){
|
||
|
return false, false, nil, errors.New("GetMyChatDecryptionKeysMapList called with Host identity.")
|
||
|
}
|
||
|
|
||
|
isValid := helpers.VerifyNetworkType(networkType)
|
||
|
if (isValid == false){
|
||
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||
|
return false, false, nil, errors.New("GetMyChatDecryptionKeySetsList called with invalid networkType: " + networkTypeString)
|
||
|
}
|
||
|
|
||
|
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
|
||
|
if (err != nil) {
|
||
|
myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
|
||
|
return false, false, nil, errors.New("CheckIfIdentityHashIsMine not verifying identity hash: " + myIdentityHashHex)
|
||
|
}
|
||
|
|
||
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||
|
|
||
|
lookupMap := map[string]string{
|
||
|
"MyIdentityHash": myIdentityHashString,
|
||
|
"NetworkType": networkTypeString,
|
||
|
}
|
||
|
|
||
|
anyExist, myChatKeysMapList, err := myChatKeysMapListDatastore.GetMapListItems(lookupMap)
|
||
|
if (err != nil){ return false, false, nil, err }
|
||
|
if (anyExist == false){
|
||
|
return true, false, nil, nil
|
||
|
}
|
||
|
|
||
|
chatDecryptionKeySetsList := make([]readMessages.ChatKeySet, 0, len(myChatKeysMapList))
|
||
|
|
||
|
for _, keySetMap := range myChatKeysMapList{
|
||
|
|
||
|
myNaclPublicKey, exists := keySetMap["NaclPublicKey"]
|
||
|
if (exists == false){
|
||
|
return false, false, nil, errors.New("Malformed myChatKeys map list: Item missing NaclPublicKey")
|
||
|
}
|
||
|
myNaclPrivateKey, exists := keySetMap["NaclPrivateKey"]
|
||
|
if (exists == false){
|
||
|
return false, false, nil, errors.New("Malformed myChatKeys map list: Item missing NaclPrivateKey")
|
||
|
}
|
||
|
myKyberPrivateKey, exists := keySetMap["KyberPrivateKey"]
|
||
|
if (exists == false){
|
||
|
return false, false, nil, errors.New("Malformed myChatKeys map list: Item missing KyberPrivateKey")
|
||
|
}
|
||
|
|
||
|
myNaclPublicKeyBytes, err := encoding.DecodeBase64StringToBytes(myNaclPublicKey)
|
||
|
if (err != nil){
|
||
|
return false, false, nil, errors.New("Malformed myChatKeys map list: NaclPublicKey is not Base64.")
|
||
|
}
|
||
|
|
||
|
if (len(myNaclPublicKeyBytes) != 32){
|
||
|
return false, false, nil, errors.New("Malformed myChatKeys map list: NaclPublicKey is invalid length.")
|
||
|
}
|
||
|
|
||
|
myNaclPublicKeyArray := [32]byte(myNaclPublicKeyBytes)
|
||
|
|
||
|
myNaclPrivateKeyBytes, err := encoding.DecodeHexStringToBytes(myNaclPrivateKey)
|
||
|
if (err != nil){
|
||
|
return false, false, nil, errors.New("Malformed myChatKeys map list: NaclPrivateKey is not Hex.")
|
||
|
}
|
||
|
|
||
|
if (len(myNaclPrivateKeyBytes) != 32){
|
||
|
return false, false, nil, errors.New("Malformed myChatKeys map list: NaclPrivateKey is invalid length.")
|
||
|
}
|
||
|
|
||
|
myNaclPrivateKeyArray := [32]byte(myNaclPrivateKeyBytes)
|
||
|
|
||
|
myKyberPrivateKeyBytes, err := encoding.DecodeHexStringToBytes(myKyberPrivateKey)
|
||
|
if (err != nil){
|
||
|
return false, false, nil, errors.New("Malformed myChatKeys map list: KyberPrivateKey is not Hex.")
|
||
|
}
|
||
|
|
||
|
if (len(myKyberPrivateKeyBytes) != 1536){
|
||
|
return false, false, nil, errors.New("Malformed myChatKeys map list: KyberPrivateKey is invalid length.")
|
||
|
}
|
||
|
|
||
|
myKyberPrivateKeyArray := [1536]byte(myKyberPrivateKeyBytes)
|
||
|
|
||
|
newChatKeySetObject := readMessages.ChatKeySet{
|
||
|
NaclPublicKey: myNaclPublicKeyArray,
|
||
|
NaclPrivateKey: myNaclPrivateKeyArray,
|
||
|
KyberPrivateKey: myKyberPrivateKeyArray,
|
||
|
}
|
||
|
|
||
|
chatDecryptionKeySetsList = append(chatDecryptionKeySetsList, newChatKeySetObject)
|
||
|
}
|
||
|
|
||
|
return true, true, chatDecryptionKeySetsList, nil
|
||
|
}
|
||
|
|
||
|
// This function generates new chat keys for an identity.
|
||
|
func GenerateNewChatKeys(myIdentityHash [16]byte, networkType byte)error{
|
||
|
|
||
|
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
|
||
|
if (err != nil) {
|
||
|
myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
|
||
|
return errors.New("GenerateNewChatKeys called with invalid identity hash: " + myIdentityHashHex)
|
||
|
}
|
||
|
|
||
|
isValid := helpers.VerifyNetworkType(networkType)
|
||
|
if (isValid == false){
|
||
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||
|
return errors.New("GenerateNewChatKeys called with invalid networkType: " + networkTypeString)
|
||
|
}
|
||
|
|
||
|
updatingMyChatKeysMutex.Lock()
|
||
|
defer updatingMyChatKeysMutex.Unlock()
|
||
|
|
||
|
currentTime := time.Now().Unix()
|
||
|
currentTimeString := helpers.ConvertInt64ToString(currentTime)
|
||
|
|
||
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||
|
|
||
|
newNaclPublicKey, newNaclPrivateKey, err := nacl.GetNewRandomPublicPrivateNaclKeys()
|
||
|
if (err != nil) { return err }
|
||
|
|
||
|
newKyberPublicKey, newKyberPrivateKey, err := kyber.GetNewRandomPublicPrivateKyberKeys()
|
||
|
if (err != nil) { return err }
|
||
|
|
||
|
newNaclPublicKeyString := encoding.EncodeBytesToBase64String(newNaclPublicKey[:])
|
||
|
newNaclPrivateKeyString := encoding.EncodeBytesToHexString(newNaclPrivateKey[:])
|
||
|
|
||
|
newKyberPublicKeyString := encoding.EncodeBytesToBase64String(newKyberPublicKey[:])
|
||
|
newKyberPrivateKeyString := encoding.EncodeBytesToHexString(newKyberPrivateKey[:])
|
||
|
|
||
|
newMapListItem := map[string]string{
|
||
|
"MyIdentityHash": myIdentityHashString,
|
||
|
"CreatedTime": currentTimeString,
|
||
|
"NetworkType": networkTypeString,
|
||
|
"NaclPublicKey": newNaclPublicKeyString,
|
||
|
"NaclPrivateKey": newNaclPrivateKeyString,
|
||
|
"KyberPublicKey": newKyberPublicKeyString,
|
||
|
"KyberPrivateKey": newKyberPrivateKeyString,
|
||
|
}
|
||
|
|
||
|
err = myChatKeysMapListDatastore.AddMapListItem(newMapListItem)
|
||
|
if (err != nil) { return err }
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
|
||
|
// This function will get a user's newest public chat keys
|
||
|
// It will create new chat keys for the provided identity if none exist
|
||
|
//Outputs:
|
||
|
// -bool: My identity exists
|
||
|
// -[32]byte: My Nacl Public key
|
||
|
// -[1568]byte: My Kyber Public key
|
||
|
// -error
|
||
|
func GetMyNewestPublicChatKeys(myIdentityHash [16]byte, networkType byte)(bool, [32]byte, [1568]byte, error){
|
||
|
|
||
|
isMine, myIdentityType, err := myIdentity.CheckIfIdentityHashIsMine(myIdentityHash)
|
||
|
if (err != nil) { return false, [32]byte{}, [1568]byte{}, err }
|
||
|
if (isMine == false){
|
||
|
return false, [32]byte{}, [1568]byte{}, nil
|
||
|
}
|
||
|
if (myIdentityType != "Mate" && myIdentityType != "Moderator"){
|
||
|
return false, [32]byte{}, [1568]byte{}, errors.New("GetMyNewestPublicChatKeys called with host identity.")
|
||
|
}
|
||
|
|
||
|
isValid := helpers.VerifyNetworkType(networkType)
|
||
|
if (isValid == false){
|
||
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||
|
return false, [32]byte{}, [1568]byte{}, errors.New("GetMyNewestPublicChatKeys called with invalid networkType: " + networkTypeString)
|
||
|
}
|
||
|
|
||
|
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
|
||
|
if (err != nil){
|
||
|
myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
|
||
|
return false, [32]byte{}, [1568]byte{}, errors.New("CheckIfIdentityHashIsMine not verifying identity hash: " + myIdentityHashHex)
|
||
|
}
|
||
|
|
||
|
updatingMyChatKeysMutex.Lock()
|
||
|
defer updatingMyChatKeysMutex.Unlock()
|
||
|
|
||
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||
|
|
||
|
lookupMap := map[string]string{
|
||
|
"MyIdentityHash": myIdentityHashString,
|
||
|
"NetworkType": networkTypeString,
|
||
|
}
|
||
|
|
||
|
anyItemsFound, myChatKeysMapList, err := myChatKeysMapListDatastore.GetMapListItems(lookupMap)
|
||
|
if (err != nil){ return false, [32]byte{}, [1568]byte{}, err }
|
||
|
if (anyItemsFound == true){
|
||
|
|
||
|
if (len(myChatKeysMapList) == 0){
|
||
|
return false, [32]byte{}, [1568]byte{}, errors.New("GetMapListItems returning empty items list after claiming items were found.")
|
||
|
}
|
||
|
|
||
|
newestChatKeysCreatedTime := int64(0)
|
||
|
var newestNaclPublicKey [32]byte
|
||
|
var newestKyberPublicKey [1568]byte
|
||
|
|
||
|
for index, chatKeysSetMap := range myChatKeysMapList{
|
||
|
|
||
|
itemMyIdentityHash, exists := chatKeysSetMap["MyIdentityHash"]
|
||
|
if (exists == false) {
|
||
|
return false, [32]byte{}, [1568]byte{}, errors.New("myMapList lookup not working properly.")
|
||
|
}
|
||
|
|
||
|
if (itemMyIdentityHash != myIdentityHashString){
|
||
|
return false, [32]byte{}, [1568]byte{}, errors.New("myMapList lookup not working properly.")
|
||
|
}
|
||
|
|
||
|
timeKeysCreated, exists := chatKeysSetMap["CreatedTime"]
|
||
|
if (exists == false) {
|
||
|
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item missing CreatedTime")
|
||
|
}
|
||
|
naclPublicKey, exists := chatKeysSetMap["NaclPublicKey"]
|
||
|
if (exists == false) {
|
||
|
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item missing NaclPublicKey")
|
||
|
}
|
||
|
kyberPublicKey, exists := chatKeysSetMap["KyberPublicKey"]
|
||
|
if (exists == false) {
|
||
|
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item missing KyberPublicKey")
|
||
|
}
|
||
|
|
||
|
naclPublicKeyBytes, err := encoding.DecodeBase64StringToBytes(naclPublicKey)
|
||
|
if (err != nil){
|
||
|
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item contains invalid NaclPublicKey: Not hex.")
|
||
|
}
|
||
|
|
||
|
if (len(naclPublicKeyBytes) != 32){
|
||
|
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item contains invalid NaclPublicKey: Invalid length.")
|
||
|
}
|
||
|
|
||
|
naclPublicKeyArray := [32]byte(naclPublicKeyBytes)
|
||
|
|
||
|
kyberPublicKeyBytes, err := encoding.DecodeBase64StringToBytes(kyberPublicKey)
|
||
|
if (err != nil){
|
||
|
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item contains invalid KyberPublicKey: Not hex.")
|
||
|
}
|
||
|
|
||
|
if (len(kyberPublicKeyBytes) != 1568){
|
||
|
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item contains invalid KyberPublicKey: Invalid length.")
|
||
|
}
|
||
|
|
||
|
kyberPublicKeyArray := [1568]byte(kyberPublicKeyBytes)
|
||
|
|
||
|
timeKeysCreatedInt64, err := helpers.ConvertStringToInt64(timeKeysCreated)
|
||
|
if (err != nil) {
|
||
|
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item contains invalid CreatedTime: " + timeKeysCreated)
|
||
|
}
|
||
|
|
||
|
if (index == 0 || newestChatKeysCreatedTime < timeKeysCreatedInt64){
|
||
|
newestChatKeysCreatedTime = timeKeysCreatedInt64
|
||
|
newestNaclPublicKey = naclPublicKeyArray
|
||
|
newestKyberPublicKey = kyberPublicKeyArray
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true, newestNaclPublicKey, newestKyberPublicKey, nil
|
||
|
}
|
||
|
|
||
|
// We must create new chat keys
|
||
|
|
||
|
currentTime := time.Now().Unix()
|
||
|
currentTimeString := helpers.ConvertInt64ToString(currentTime)
|
||
|
|
||
|
newNaclPublicKey, newNaclPrivateKey, err := nacl.GetNewRandomPublicPrivateNaclKeys()
|
||
|
if (err != nil) { return false, [32]byte{}, [1568]byte{}, err }
|
||
|
|
||
|
newKyberPublicKey, newKyberPrivateKey, err := kyber.GetNewRandomPublicPrivateKyberKeys()
|
||
|
if (err != nil) { return false, [32]byte{}, [1568]byte{}, err }
|
||
|
|
||
|
newNaclPublicKeyString := encoding.EncodeBytesToBase64String(newNaclPublicKey[:])
|
||
|
newNaclPrivateKeyString := encoding.EncodeBytesToHexString(newNaclPrivateKey[:])
|
||
|
|
||
|
newKyberPublicKeyString := encoding.EncodeBytesToBase64String(newKyberPublicKey[:])
|
||
|
newKyberPrivateKeyString := encoding.EncodeBytesToHexString(newKyberPrivateKey[:])
|
||
|
|
||
|
newChatKeysSetMap := map[string]string{
|
||
|
"MyIdentityHash": myIdentityHashString,
|
||
|
"NetworkType": networkTypeString,
|
||
|
"CreatedTime": currentTimeString,
|
||
|
"NaclPublicKey": newNaclPublicKeyString,
|
||
|
"NaclPrivateKey": newNaclPrivateKeyString,
|
||
|
"KyberPublicKey": newKyberPublicKeyString,
|
||
|
"KyberPrivateKey": newKyberPrivateKeyString,
|
||
|
}
|
||
|
|
||
|
err = myChatKeysMapListDatastore.AddMapListItem(newChatKeysSetMap)
|
||
|
if (err != nil) { return false, [32]byte{}, [1568]byte{}, err }
|
||
|
|
||
|
return true, newNaclPublicKey, newKyberPublicKey, nil
|
||
|
}
|
||
|
|
||
|
// This function is only called when a new profile is added to myBroadcasts
|
||
|
func SetMyChatKeysLatestUpdateTime(myIdentityHash [16]byte, networkType byte, newLatestUpdateTime int64)error{
|
||
|
|
||
|
isMine, myIdentityType, err := myIdentity.CheckIfIdentityHashIsMine(myIdentityHash)
|
||
|
if (err != nil) { return err }
|
||
|
if (isMine == false){
|
||
|
return errors.New("SetMyChatKeysLatestUpdateTime called with identity that is not mine.")
|
||
|
}
|
||
|
if (myIdentityType != "Mate" && myIdentityType != "Moderator"){
|
||
|
return errors.New("SetMyChatKeysLatestUpdateTime called with Host identity.")
|
||
|
}
|
||
|
|
||
|
isValid := helpers.VerifyNetworkType(networkType)
|
||
|
if (isValid == false){
|
||
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||
|
return errors.New("SetMyChatKeysLatestUpdateTime called with invalid networkType: " + networkTypeString)
|
||
|
}
|
||
|
|
||
|
updatingMyChatKeysLatestUpdateTimeMutex.Lock()
|
||
|
defer updatingMyChatKeysLatestUpdateTimeMutex.Unlock()
|
||
|
|
||
|
exists, existingLatestUpdateTime, err := GetMyChatKeysLatestUpdateTime(myIdentityHash, networkType)
|
||
|
if (err != nil) { return err }
|
||
|
if (exists == true){
|
||
|
if (existingLatestUpdateTime > newLatestUpdateTime) {
|
||
|
// This would only happen if our system clock was invalid, and became valid
|
||
|
// We will log this, but allow our latestUpdateTime to be updated
|
||
|
err := logger.AddLogEntry("General", "Existing latest chat keys update time is later than new update time.")
|
||
|
if (err != nil) { return err }
|
||
|
|
||
|
} else if (existingLatestUpdateTime == newLatestUpdateTime){
|
||
|
// No update is needed.
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
|
||
|
if (err != nil){
|
||
|
myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
|
||
|
return errors.New("CheckIfIdentityHashIsMine not verifying identity hash: " + myIdentityHashHex)
|
||
|
}
|
||
|
|
||
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||
|
|
||
|
mapEntryKey := myIdentityHashString + "@" + networkTypeString
|
||
|
|
||
|
newLatestUpdateTimeString := helpers.ConvertInt64ToString(newLatestUpdateTime)
|
||
|
|
||
|
err = myChatKeysLatestUpdateTimeMapDatastore.SetMapEntry(mapEntryKey, newLatestUpdateTimeString)
|
||
|
if (err != nil) { return err }
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
|
||
|
//Outputs:
|
||
|
// -bool: Update time exists (wont exist if profile has never been broadcast, or existing profile is not imported yet)
|
||
|
// -int64: Current latest update time
|
||
|
// -error
|
||
|
func GetMyChatKeysLatestUpdateTime(myIdentityHash [16]byte, networkType byte)(bool, int64, error){
|
||
|
|
||
|
isMine, myIdentityType, err := myIdentity.CheckIfIdentityHashIsMine(myIdentityHash)
|
||
|
if (err != nil) { return false, 0, err }
|
||
|
if (isMine == false){
|
||
|
return false, 0, errors.New("GetMyChatKeysLatestUpdateTime called with identity that is not mine.")
|
||
|
}
|
||
|
if (myIdentityType != "Mate" && myIdentityType != "Moderator"){
|
||
|
return false, 0, errors.New("GetMyChatKeysLatestUpdateTime called with Host identity.")
|
||
|
}
|
||
|
|
||
|
isValid := helpers.VerifyNetworkType(networkType)
|
||
|
if (isValid == false){
|
||
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||
|
return false, 0, errors.New("GetMyChatKeysLatestUpdateTime called with invalid networkType: " + networkTypeString)
|
||
|
}
|
||
|
|
||
|
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
|
||
|
if (err != nil){
|
||
|
myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
|
||
|
return false, 0, errors.New("CheckIfIdentityHashIsMine not verifying my identity hash: " + myIdentityHashHex)
|
||
|
}
|
||
|
|
||
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||
|
|
||
|
mapEntryKey := myIdentityHashString + "@" + networkTypeString
|
||
|
|
||
|
exists, latestUpdateTimeString, err := myChatKeysLatestUpdateTimeMapDatastore.GetMapEntry(mapEntryKey)
|
||
|
if (err != nil) { return false, 0, err }
|
||
|
if (exists == false) {
|
||
|
return false, 0, nil
|
||
|
}
|
||
|
|
||
|
latestUpdateTimeInt64, err := helpers.ConvertStringToInt64(latestUpdateTimeString)
|
||
|
if (err != nil) {
|
||
|
return false, 0, errors.New("myChatKeysLatestUpdateTimeMapDatastore is corrupt: Contains invalid latestUpdateTime: " + latestUpdateTimeString)
|
||
|
}
|
||
|
|
||
|
return true, latestUpdateTimeInt64, nil
|
||
|
}
|
||
|
|
||
|
|
||
|
// This function is used to keep track of the user's newest broadcasted chat keys
|
||
|
// We need to do this because we need to be able to tell if the profile we are broadcasting contains new keys
|
||
|
// This is stored seperately from myBroadcasts
|
||
|
// This datastore can prevent users from having to update their latestChatKeysUpdateTime when moving to a new device, if they import their keys
|
||
|
func SetMyNewestBroadcastPublicChatKeys(myIdentityHash [16]byte, networkType byte, naclKey [32]byte, kyberKey [1568]byte)error{
|
||
|
|
||
|
isMine, myIdentityType, err := myIdentity.CheckIfIdentityHashIsMine(myIdentityHash)
|
||
|
if (err != nil) { return err }
|
||
|
if (isMine == false){
|
||
|
return errors.New("SetMyNewestBroadcastPublicChatKeys called with identity that is not mine.")
|
||
|
}
|
||
|
if (myIdentityType != "Mate" && myIdentityType != "Moderator"){
|
||
|
return errors.New("SetMyNewestBroadcastPublicChatKeys called with Host identity.")
|
||
|
}
|
||
|
|
||
|
isValid := helpers.VerifyNetworkType(networkType)
|
||
|
if (isValid == false){
|
||
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||
|
return errors.New("SetMyNewestBroadcastPublicChatKeys called with invalid networkType: " + networkTypeString)
|
||
|
}
|
||
|
|
||
|
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
|
||
|
if (err != nil){
|
||
|
myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
|
||
|
return errors.New("CheckIfIdentityHashIsMine not verifying my identity hash: " + myIdentityHashHex)
|
||
|
}
|
||
|
|
||
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||
|
|
||
|
mapEntryKey := myIdentityHashString + "@" + networkTypeString
|
||
|
|
||
|
naclKeyEncoded := encoding.EncodeBytesToBase64String(naclKey[:])
|
||
|
kyberKeyEncoded := encoding.EncodeBytesToBase64String(kyberKey[:])
|
||
|
|
||
|
newEntryValue := naclKeyEncoded + "+" + kyberKeyEncoded
|
||
|
|
||
|
err = myNewestBroadcastPublicChatKeysMapDatastore.SetMapEntry(mapEntryKey, newEntryValue)
|
||
|
if (err != nil) { return err }
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
//Outputs:
|
||
|
// -bool: My identity found
|
||
|
// -bool: Any keys found
|
||
|
// -[32]byte: Newest broadcast Nacl key (Encoded base64)
|
||
|
// -[1568]byte: Newest broadcast Kyber key (Encoded base64)
|
||
|
// -error
|
||
|
func GetMyNewestBroadcastPublicChatKeys(myIdentityHash [16]byte, networkType byte)(bool, bool, [32]byte, [1568]byte, error){
|
||
|
|
||
|
isMine, myIdentityType, err := myIdentity.CheckIfIdentityHashIsMine(myIdentityHash)
|
||
|
if (err != nil) { return false, false, [32]byte{}, [1568]byte{}, err }
|
||
|
if (isMine == false){
|
||
|
return false, false, [32]byte{}, [1568]byte{}, nil
|
||
|
}
|
||
|
if (myIdentityType != "Mate" && myIdentityType != "Moderator"){
|
||
|
return false, false, [32]byte{}, [1568]byte{}, errors.New("GetMyNewestBroadcastPublicChatKeys called with Host identity.")
|
||
|
}
|
||
|
|
||
|
isValid := helpers.VerifyNetworkType(networkType)
|
||
|
if (isValid == false){
|
||
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||
|
return false, false, [32]byte{}, [1568]byte{}, errors.New("GetMyNewestBroadcastPublicChatKeys called with invalid networkType: " + networkTypeString)
|
||
|
}
|
||
|
|
||
|
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
|
||
|
if (err != nil){
|
||
|
myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
|
||
|
return false, false, [32]byte{}, [1568]byte{}, errors.New("CheckIfIdentityHashIsMine not verifying my identity hash: " + myIdentityHashHex)
|
||
|
}
|
||
|
|
||
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||
|
|
||
|
mapEntryKey := myIdentityHashString + "@" + networkTypeString
|
||
|
|
||
|
exists, mapItemValue, err := myNewestBroadcastPublicChatKeysMapDatastore.GetMapEntry(mapEntryKey)
|
||
|
if (err != nil) { return false, false, [32]byte{}, [1568]byte{}, err }
|
||
|
if (exists == false){
|
||
|
return true, false, [32]byte{}, [1568]byte{}, nil
|
||
|
}
|
||
|
|
||
|
naclKeyString, kyberKeyString, delimiterFound := strings.Cut(mapItemValue, "+")
|
||
|
if (delimiterFound == false){
|
||
|
return false, false, [32]byte{}, [1568]byte{}, errors.New("Malformed myNewestBroadcastPublicChatKeysMapDatastore item value: " + mapItemValue)
|
||
|
}
|
||
|
|
||
|
naclKeyBytes, err := encoding.DecodeBase64StringToBytes(naclKeyString)
|
||
|
if (err != nil){
|
||
|
return false, false, [32]byte{}, [1568]byte{}, errors.New("Malformed myNewestBroadcastPublicChatKeysMapDatastore item value: Invalid NaclKey: Not Base64: " + naclKeyString)
|
||
|
}
|
||
|
|
||
|
if (len(naclKeyBytes) != 32){
|
||
|
return false, false, [32]byte{}, [1568]byte{}, errors.New("Malformed myNewestBroadcastPublicChatKeysMapDatastore item value: Invalid NaclKey: Invalid length: " + naclKeyString)
|
||
|
}
|
||
|
|
||
|
naclKey := [32]byte(naclKeyBytes)
|
||
|
|
||
|
kyberKeyBytes, err := encoding.DecodeBase64StringToBytes(kyberKeyString)
|
||
|
if (err != nil){
|
||
|
return false, false, [32]byte{}, [1568]byte{}, errors.New("Malformed myNewestBroadcastPublicChatKeysMapDatastore item value: Invalid KyberKey: Not Base64: " + kyberKeyString)
|
||
|
}
|
||
|
|
||
|
if (len(kyberKeyBytes) != 1568){
|
||
|
return false, false, [32]byte{}, [1568]byte{}, errors.New("Malformed myNewestBroadcastPublicChatKeysMapDatastore item value: Invalid KyberKey: Invalid length: " + kyberKeyString)
|
||
|
}
|
||
|
|
||
|
kyberKey := [1568]byte(kyberKeyBytes)
|
||
|
|
||
|
return true, true, naclKey, kyberKey, nil
|
||
|
}
|
||
|
|
||
|
|
||
|
|