Skip to content

Commit

Permalink
Add shardeum version check for seed node in restore network
Browse files Browse the repository at this point in the history
  • Loading branch information
tanuj-shardeum authored and mhanson-github committed Sep 2, 2024
1 parent 93690fc commit 7bccf0e
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 8 deletions.
64 changes: 57 additions & 7 deletions src/API.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,18 @@ export function registerRoutes(server: FastifyInstance<Server, IncomingMessage,
* CZ adds AZ's join reqeuest to cycle zero and sets AZ as cycleRecipient
*/
type NodeListRequest = FastifyRequest<{
Body: P2P.FirstNodeInfo & Crypto.SignedMessage
Body: {
joinRequest: {
appJoinData: {
shardeumVersion: string
minVersion: string
activeVersion: string
latestVersion: string
operatorCLIVersion: string
operatorGUIVersion: string
}
} & P2P.FirstNodeInfo
} & Crypto.SignedMessage
}>

server.get('/myip', function (request, reply) {
Expand All @@ -77,18 +88,21 @@ export function registerRoutes(server: FastifyInstance<Server, IncomingMessage,
server.post('/nodelist', (request: NodeListRequest, reply) => {
profilerInstance.profileSectionStart('POST_nodelist')
nestedCountersInstance.countEvent('consensor', 'POST_nodelist', 1)
const signedFirstNodeInfo = request.body
const requestBody = request.body
// eslint-disable-next-line no-constant-condition
if(true) Logger.mainLogger.debug('POST /nodelist requestBody:', requestBody)

Check warning

Code scanning / CodeQL

Log injection Medium

Log entry depends on a
user-provided value
.

if (State.isFirst && NodeList.isEmpty() && !NodeList.foundFirstNode) {
try {
const isSignatureValid = Crypto.verify(signedFirstNodeInfo)
const isSignatureValid = Crypto.verify(requestBody)
if (!isSignatureValid) {
Logger.mainLogger.error('Invalid signature', signedFirstNodeInfo)
Logger.mainLogger.error('Invalid signature', requestBody)

Check warning

Code scanning / CodeQL

Log injection Medium

Log entry depends on a
user-provided value
.
reply.send({ success: false, error: 'Invalid signature' })
return
}
} catch (e) {
Logger.mainLogger.error(e)
Logger.mainLogger.error('Signature verification failed', requestBody)

Check warning

Code scanning / CodeQL

Log injection Medium

Log entry depends on a
user-provided value
.
reply.send({ success: false, error: 'Signature verification failed' })
return
}
Expand All @@ -98,16 +112,52 @@ export function registerRoutes(server: FastifyInstance<Server, IncomingMessage,
return
}
NodeList.toggleFirstNode()
const ip = signedFirstNodeInfo.nodeInfo.externalIp
const port = signedFirstNodeInfo.nodeInfo.externalPort
const publicKey = signedFirstNodeInfo.nodeInfo.publicKey

const signedFirstNodeInfo = requestBody.joinRequest.nodeInfo
const appJoinData = requestBody.joinRequest.appJoinData

const ip = signedFirstNodeInfo.externalIp
const port = signedFirstNodeInfo.externalPort
const publicKey = signedFirstNodeInfo.publicKey

const firstNode: NodeList.ConsensusNodeInfo = {
ip,
port,
publicKey,
}

// eslint-disable-next-line no-constant-condition
if (true) {
Logger.mainLogger.debug('POST /nodelist firstNode:', firstNode)
Logger.mainLogger.debug('POST /nodelist appJoinData:', appJoinData)

Check warning

Code scanning / CodeQL

Log injection Medium

Log entry depends on a
user-provided value
.
}


const networkAccount: AccountDB.AccountCopy | string = getGlobalNetworkAccount(false)
Logger.mainLogger.debug('networkAccount', networkAccount)

if (networkAccount) {
Logger.mainLogger.debug('POST /nodelist networkAccount exists validating node join request version')
if (
typeof networkAccount !== 'string' &&
!NodeList.isValidVersion(
networkAccount?.data?.minVersion,
networkAccount?.data?.latestVersion,
appJoinData.shardeumVersion
)
) {
Logger.mainLogger.debug(
`Invalid version of the node: ${appJoinData.shardeumVersion}, required minVersion: ${networkAccount?.data?.minVersion}, required latestVersion: ${networkAccount?.data?.latestVersion}`

Check warning

Code scanning / CodeQL

Log injection Medium

Log entry depends on a
user-provided value
.
)
reply.send({ success: false, error: 'Invalid version' })
return
} else {
Logger.mainLogger.debug('POST /nodelist network account is a string or version is valid: ', typeof networkAccount)
}
} else {
Logger.mainLogger.debug('POST /nodelist network account does not exist')
}

Data.initSocketClient(firstNode)

// Add first node to NodeList
Expand Down
2 changes: 1 addition & 1 deletion src/GlobalAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export interface GlobalAccountsHashAndTimestamp {
export const globalAccountsMap = new Map<string, GlobalAccountsHashAndTimestamp>()
const appliedConfigChanges = new Set<string>()

export function getGlobalNetworkAccount(hash: boolean): object | string {
export function getGlobalNetworkAccount(hash: boolean): AccountDB.AccountCopy | string {
if (hash) {
return cachedGlobalNetworkAccountHash
}
Expand Down
30 changes: 30 additions & 0 deletions src/NodeList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -416,3 +416,33 @@ export function toggleFirstNode(): void {
foundFirstNode = !foundFirstNode
Logger.mainLogger.debug('foundFirstNode', foundFirstNode)
}

export function isEqualOrNewerVersion(minimumVersion: string, nodeVersion: string): boolean {
if (minimumVersion === nodeVersion) {
return true
}

const minVerParts = minimumVersion.split('.')
const nodeVerParts = nodeVersion.split('.')

/* eslint-disable security/detect-object-injection */
for (let i = 0; i < nodeVerParts.length; i++) {
const nodeV = ~~nodeVerParts[i] // parse int
const minV = ~~minVerParts[i] // parse int
if (nodeV > minV) return true
if (nodeV < minV) return false
}
/* eslint-enable security/detect-object-injection */
return false
}

export function isEqualOrOlderVersion(maximumVersion: string, nodeVersion: string): boolean {
return isEqualOrNewerVersion(nodeVersion, maximumVersion)
}

export function isValidVersion(minimumVersion: string, latestVersion: string, nodeVersion: string): boolean {
const equalOrNewer = isEqualOrNewerVersion(minimumVersion, nodeVersion)
const equalOrOlder = isEqualOrOlderVersion(latestVersion, nodeVersion)

return equalOrNewer && equalOrOlder
}

0 comments on commit 7bccf0e

Please sign in to comment.