2024-04-11 15:51:56 +02:00
// parametersStorage provides functions to store and retrieve network parameters
package parametersStorage
//TODO: Create a job to prune old parameters
import "seekia/internal/parameters/readParameters"
import "seekia/internal/helpers"
import "seekia/internal/localFilesystem"
import "seekia/internal/encoding"
import "bytes"
import goFilepath "path/filepath"
import "strings"
import "errors"
import "slices"
//TODO: The key of the master admin who can change the admin permissions
const masterAdminPublicKey string = "TODO"
//Outputs:
// -bool: Parameters to add are well formed
// -bool: Admin permissions found (we cannot add parameters without these)
// -error
func AddParameters ( inputParameters [ ] byte ) ( bool , bool , error ) {
2024-06-11 06:59:06 +02:00
ableToRead , _ , parametersNetworkType , listOfAdmins , parametersType , parametersCreationTime , _ , err := readParameters . ReadParameters ( true , inputParameters )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return false , false , err }
if ( ableToRead == false ) {
return false , false , nil
}
2024-06-11 06:59:06 +02:00
adminParametersFound , parametersAreAuthorized , err := verifyParametersAreAuthorized ( parametersType , parametersNetworkType , parametersCreationTime , listOfAdmins )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return false , false , err }
if ( adminParametersFound == false ) {
// We do not have admin parameters. We cannot determine if parameters to add are authorized
return false , false , nil
}
if ( parametersAreAuthorized == false ) {
// Parameters are not authorized.
// Could be malicious host who sent parameters, or admin permissions were updated and we/they do not have them yet
return true , true , nil
}
// We check if parameters already exist that are newer
2024-06-11 06:59:06 +02:00
parametersFound , _ , _ , existingParametersCreationTime , err := GetAuthorizedParameters ( parametersType , parametersNetworkType )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return false , false , err }
if ( parametersFound == true ) {
2024-06-11 06:59:06 +02:00
if ( existingParametersCreationTime >= parametersCreationTime ) {
2024-04-11 15:51:56 +02:00
// These parameters are older than our existing stored authorized parameters.
// We will not add them.
return true , true , nil
}
}
seekiaDirectory , err := localFilesystem . GetSeekiaDataFolderPath ( )
if ( err != nil ) { return false , false , err }
networkTypeString := helpers . ConvertByteToString ( parametersNetworkType )
networkTypeFoldername := "Network" + networkTypeString
parametersFolderpath := goFilepath . Join ( seekiaDirectory , "Parameters" , networkTypeFoldername )
parametersFilename := parametersType + ".messagepack"
err = localFilesystem . CreateOrOverwriteFile ( inputParameters , parametersFolderpath , parametersFilename )
if ( err != nil ) { return false , false , err }
return true , true , nil
}
// This function will return parameters that are signed by known admins
//Outputs:
// -bool: Requested parameters found and signed by valid admins
// -[]byte: Parameters bytes
// -map[string]string: Parameters map
2024-06-11 06:59:06 +02:00
// -int64: Parameters creation time
2024-04-11 15:51:56 +02:00
// -error
func GetAuthorizedParameters ( parametersType string , networkType byte ) ( bool , [ ] byte , map [ string ] string , int64 , error ) {
isValid := readParameters . VerifyParametersType ( parametersType )
if ( isValid == false ) {
return false , nil , nil , 0 , errors . New ( "GetAuthorizedParameters called with invalid parametersType: " + parametersType )
}
isValid = helpers . VerifyNetworkType ( networkType )
if ( isValid == false ) {
networkTypeString := helpers . ConvertByteToString ( networkType )
return false , nil , nil , 0 , errors . New ( "GetAuthorizedParameters called with invalid networkType: " + networkTypeString )
}
parametersExist , storedParametersBytes , err := getStoredParameters ( parametersType , networkType )
if ( err != nil ) { return false , nil , nil , 0 , err }
if ( parametersExist == false ) {
return false , nil , nil , 0 , nil
}
2024-06-11 06:59:06 +02:00
ableToRead , _ , parametersNetworkType , listOfSigners , currentParametersType , parametersCreationTime , parametersMap , err := readParameters . ReadParameters ( true , storedParametersBytes )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return false , nil , nil , 0 , err }
if ( ableToRead == false ) {
return false , nil , nil , 0 , errors . New ( "Stored parameters are corrupt: storing corrupt " + parametersType + "parameter." )
}
if ( parametersNetworkType != networkType ) {
return false , nil , nil , 0 , errors . New ( "getStoredParameters returning different networkType parameters" )
}
if ( currentParametersType != parametersType ) {
return false , nil , nil , 0 , errors . New ( "getStoredParameters returning different parametersType parameters" )
}
2024-06-11 06:59:06 +02:00
adminPermissionsFound , parametersAreAuthorized , err := verifyParametersAreAuthorized ( parametersType , networkType , parametersCreationTime , listOfSigners )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return false , nil , nil , 0 , err }
if ( adminPermissionsFound == false || parametersAreAuthorized == false ) {
return false , nil , nil , 0 , nil
}
2024-06-11 06:59:06 +02:00
return true , storedParametersBytes , parametersMap , parametersCreationTime , nil
2024-04-11 15:51:56 +02:00
}
//Outputs:
// -bool: Admin permissions found
// -bool: Parameters are authorized
// -error
2024-06-11 06:59:06 +02:00
func verifyParametersAreAuthorized ( parametersType string , networkType byte , parametersCreationTime int64 , parametersSigners [ ] [ 32 ] byte ) ( bool , bool , error ) {
2024-04-11 15:51:56 +02:00
containsDuplicates , _ := helpers . CheckIfListContainsDuplicates ( parametersSigners )
if ( containsDuplicates == true ) {
return false , false , errors . New ( "verifyParametersAreAuthorized called with parametersSigners list containing duplicates." )
}
parametersExist , adminPermissionsParameters , err := getStoredParameters ( "AdminPermissions" , networkType )
if ( err != nil ) { return false , false , err }
if ( parametersExist == false ) {
return false , false , nil
}
ableToRead , _ , parametersNetworkType , listOfAdmins , currentParametersType , _ , adminPermissionsMap , err := readParameters . ReadParameters ( true , adminPermissionsParameters )
if ( err != nil ) { return false , false , err }
if ( ableToRead == false ) {
return false , false , errors . New ( "Parameters storage corrupt: Storing invalid AdminPermissions." )
}
if ( parametersNetworkType != networkType ) {
return false , false , errors . New ( "getStoredParameters returning parameters of a different networkType" )
}
if ( currentParametersType != "AdminPermissions" ) {
return false , false , errors . New ( "getStoredParameters returning parameters of a different parametersType" )
}
if ( len ( listOfAdmins ) != 1 ) {
return false , false , errors . New ( "Parameters storage is corrupt: storing AdminPermissions with more than 1 signer." )
}
masterAdminPublicKeyBytes , err := encoding . DecodeHexStringToBytes ( masterAdminPublicKey )
if ( err != nil ) {
return false , false , errors . New ( "Master admin public key is malformed: " + masterAdminPublicKey + ". Reason: " + err . Error ( ) )
}
areEqual := bytes . Equal ( listOfAdmins [ 0 ] [ : ] , masterAdminPublicKeyBytes )
if ( areEqual == false ) {
return false , false , errors . New ( "Parameters storage is corrupt: storing AdminPermissions with different admin key." )
}
authorizedAdminsListString , exists := adminPermissionsMap [ parametersType + "_AuthorizedAdmins" ]
if ( exists == false ) {
return false , false , errors . New ( "Stored AdminPermissions parameters missing " + parametersType + "_AuthorizedAdmins" )
}
authorizedAdminsList := strings . Split ( authorizedAdminsListString , "+" )
if ( len ( authorizedAdminsList ) == 0 ) {
return false , false , errors . New ( "Stored AdminPermissions parameters contains empty authorizedAdmins list" )
}
authorizedAdminKeysList := make ( [ ] [ 32 ] byte , 0 , len ( authorizedAdminsList ) )
for _ , adminPublicKeyHex := range authorizedAdminsList {
adminPublicKey , err := encoding . DecodeHexStringToBytes ( adminPublicKeyHex )
if ( err != nil ) {
return false , false , errors . New ( "Stored AdminPermissions parameters contains empty authorizedAdmins list: Key not hex." )
}
if ( len ( adminPublicKey ) != 32 ) {
return false , false , errors . New ( "Stored AdminPermissions parameters contains empty authorizedAdmins list: Key is invalid length." )
}
adminPublicKeyArray := [ 32 ] byte ( adminPublicKey )
authorizedAdminKeysList = append ( authorizedAdminKeysList , adminPublicKeyArray )
}
minimumSigners , exists := adminPermissionsMap [ parametersType + "_MinimumSigners" ]
if ( exists == false ) {
return false , false , errors . New ( "Parameters storage is corrupt: AdminPermissions missing MinimumSigners but contains AuthorizedAdmins" )
}
minimumNumberOfSigners , err := helpers . ConvertStringToInt ( minimumSigners )
if ( err != nil ) {
return false , false , errors . New ( "Parameters storage is corrupt: AdminPermissions contains invalid minimumSigners: " + minimumSigners )
}
if ( len ( authorizedAdminKeysList ) < minimumNumberOfSigners ) {
return false , false , errors . New ( "Parameters storage is corrupt: AdminPermissions contains less authorizedAdmins than minimumSigners" )
}
2024-06-11 06:59:06 +02:00
minimumCreationTime , exists := adminPermissionsMap [ parametersType + "_MinimumCreationTime" ]
2024-04-11 15:51:56 +02:00
if ( exists == false ) {
2024-06-11 06:59:06 +02:00
return false , false , errors . New ( "Parameters storage is corrupt: AdminPermissions missing minimumCreationTime but contains AuthorizedAdmins for parameterType." )
2024-04-11 15:51:56 +02:00
}
2024-06-11 06:59:06 +02:00
minimumCreationTimeInt64 , err := helpers . ConvertStringToInt64 ( minimumCreationTime )
2024-04-11 15:51:56 +02:00
if ( err != nil ) {
2024-06-11 06:59:06 +02:00
return false , false , errors . New ( "Parameters storage is corrupt: AdminPermissions contains invalid minimumCreationTime: " + minimumCreationTime )
2024-04-11 15:51:56 +02:00
}
2024-06-11 06:59:06 +02:00
if ( parametersCreationTime < minimumCreationTimeInt64 ) {
2024-04-11 15:51:56 +02:00
return false , false , nil
}
verifiedAdminsCount := 0
for _ , adminPublicKey := range parametersSigners {
isInList := slices . Contains ( authorizedAdminKeysList , adminPublicKey )
if ( isInList == true ) {
verifiedAdminsCount += 1
}
}
if ( verifiedAdminsCount < minimumNumberOfSigners ) {
// This parameters file does not have enough authorized signers
// Either the provider of the parameters file is malicious, or the permissions file has updated
// and the provider/we have not received the newest file
return true , false , nil
}
return true , true , nil
}
//Outputs:
// -bool: Parameters exist
// -[]byte: Parameters bytes
// -error
func getStoredParameters ( parametersType string , networkType byte ) ( bool , [ ] byte , error ) {
seekiaDirectory , err := localFilesystem . GetSeekiaDataFolderPath ( )
if ( err != nil ) { return false , nil , err }
networkTypeString := helpers . ConvertByteToString ( networkType )
networkTypeFoldername := "Network" + networkTypeString
parametersFilename := parametersType + ".messagepack"
parametersFilepath := goFilepath . Join ( seekiaDirectory , "Parameters" , networkTypeFoldername , parametersFilename )
exists , fileBytes , err := localFilesystem . GetFileContents ( parametersFilepath )
if ( err != nil ) { return false , nil , err }
if ( exists == false ) {
return false , nil , nil
}
return true , fileBytes , nil
}