Skip to content

Commit

Permalink
Merge pull request #203 from decentraland/fix/receive-old-signatures
Browse files Browse the repository at this point in the history
fix: Signatures with V 0 or 1
  • Loading branch information
LautaroPetaccio committed Dec 20, 2022
2 parents 6c0d93e + 65f44c8 commit 5feee14
Show file tree
Hide file tree
Showing 7 changed files with 289 additions and 36 deletions.
4 changes: 3 additions & 1 deletion src/logic/rentals/ethereum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ethers } from "ethers"
import { ChainId } from "@dcl/schemas"
import { _TypedDataEncoder } from "@ethersproject/hash"
import { ContractData, ContractName, getContract } from "decentraland-transactions"
import { hasECDSASignatureAValidV } from "../../ports/rentals/utils"
import { ContractRentalListing, RentalListingSignatureData } from "./types"

async function buildRentalListingSignatureData(
Expand Down Expand Up @@ -52,5 +53,6 @@ export async function verifyRentalsListingSignature(
rentalListingSignatureData.signature
)

return signingAddress.toLowerCase() === rentalListingSignatureData.values.signer
const isVValid = hasECDSASignatureAValidV(rentalListing.signature)
return signingAddress.toLowerCase() === rentalListingSignatureData.values.signer && isVValid
}
35 changes: 28 additions & 7 deletions src/ports/rentals/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
IndexUpdateEventType,
} from "./types"
import { buildQueryParameters } from "./graph"
import { generateECDSASignatureWithInvalidV, generateECDSASignatureWithValidV, hasECDSASignatureAValidV } from "./utils"

export async function createRentalsComponent(
components: Pick<AppComponents, "database" | "logs" | "marketplaceSubgraph" | "rentalsSubgraph" | "config">
Expand Down Expand Up @@ -251,6 +252,11 @@ export async function createRentalsComponent(
rental.chainId
)
if (!isSignatureValid) {
if (!hasECDSASignatureAValidV(rental.signature)) {
logger.error(buildLogMessageForRental("Invalid signature: ECDSA signature with V as 0 or 1"))
throw new InvalidSignature("The server does not accept ECDSA signatures with V as 0 or 1")
}
logger.error(buildLogMessageForRental("Invalid signature"))
throw new InvalidSignature()
}

Expand Down Expand Up @@ -482,8 +488,9 @@ export async function createRentalsComponent(
}

const rentalData = rentalQueryResult.rows[0]
const signature = generateECDSASignatureWithValidV(rentalData.signature)
const [indexerRentals, [indexerNFT], indexerIndexesUpdate] = await Promise.all([
getRentalsFromIndexer({ first: 1, filterBy: { signature: rentalData.signature } }),
getRentalsFromIndexer({ first: 1, filterBy: { signature } }),
getNFTsFromIndexer({
filterBy: { contractAddress: rentalData.contract_address, tokenId: rentalData.token_id },
first: 1,
Expand Down Expand Up @@ -517,7 +524,7 @@ export async function createRentalsComponent(
)
)

// If the nft has been transfered, but not due to a rent starting
// If the nft has been transferred, but not due to a rent starting
// Cancel the rental listing that now has a different owner
if (rentalData.status === RentalStatus.OPEN && indexerNFT.owner.address !== rentalData.lessor) {
database.query(SQL`UPDATE rentals SET status = ${RentalStatus.CANCELLED} WHERE id = ${rentalData.id}`)
Expand All @@ -533,14 +540,24 @@ export async function createRentalsComponent(
indexerRentals[0].ownerHasClaimedAsset ? RentalStatus.CLAIMED : RentalStatus.EXECUTED
}, rented_days = ${indexerRentals[0].rentalDays}, period_chosen = ${
rentalData.period_id
}, started_at = ${new Date(fromSecondsToMilliseconds(Number(indexerRentals[0].startedAt)))} WHERE id = ${
rentalData.id
}`
}, started_at = ${new Date(
fromSecondsToMilliseconds(Number(indexerRentals[0].startedAt))
)}, signature = ${signature} WHERE id = ${rentalData.id}`
),
database.query(
SQL`UPDATE rentals_listings SET tenant = ${indexerRentals[0].tenant} WHERE id = ${rentalData.id}`
)
)
} else if (
indexerRentalLastUpdate === 0 &&
rentalData.status === RentalStatus.OPEN &&
!hasECDSASignatureAValidV(rentalData.signature)
) {
logger.info(`[Refresh][Update rental signature][${rentalId}]`)
// If the rental has not been executed and the signature is invalid, change it.
promisesOfUpdate.push(
database.query(SQL`UPDATE rentals SET signature = ${signature} WHERE id = ${rentalData.id}`)
)
}

// Identify if there's any blockchain nonce update
Expand Down Expand Up @@ -724,7 +741,11 @@ export async function createRentalsComponent(
SQL`
SELECT rentals.id, lessor, status, started_at, periods.id period_id, periods.max_days, periods.min_days
FROM rentals, rentals_listings, periods
WHERE rentals.id = rentals_listings.id AND rentals.signature = ${rental.signature} AND periods.rental_id = rentals.id
WHERE rentals.id = rentals_listings.id AND rentals.signature = ${
rental.signature
} OR rentals.signature = ${generateECDSASignatureWithInvalidV(
rental.signature
)} AND periods.rental_id = rentals.id
`
)
logger.debug(
Expand All @@ -745,7 +766,7 @@ export async function createRentalsComponent(
dbRental.period_id
}, started_at = ${new Date(fromSecondsToMilliseconds(Number(rental.startedAt)))}, status = ${
rental.ownerHasClaimedAsset ? RentalStatus.CLAIMED : RentalStatus.EXECUTED
} WHERE id = ${dbRental.id}`
}, signature = ${generateECDSASignatureWithValidV(rental.signature)} WHERE id = ${dbRental.id}`
),
client.query(
SQL`UPDATE rentals SET status = ${RentalStatus.CLAIMED} WHERE contract_address = ${rental.contractAddress} AND token_id = ${rental.tokenId} AND status = ${RentalStatus.EXECUTED} AND started_at < ${dbRental.started_at}`
Expand Down
4 changes: 2 additions & 2 deletions src/ports/rentals/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class RentalNotFound extends Error {
}

export class InvalidSignature extends Error {
constructor() {
super("The provided signature is invalid")
constructor(public reason?: string) {
super(`The provided signature is invalid${reason ? `: ${reason}` : ""}`)
}
}
46 changes: 46 additions & 0 deletions src/ports/rentals/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Gets the last byte as a number from the a signature.
* @param signature - A ECDSA signature.
* @returns the last byte of the given signature.
*/
function getLastECDSASignatureByte(signature: string) {
return Number.parseInt(signature.slice(-2), 16)
}

/**
* Checks wether a ECDSA signature has a valid V.
* @param signature - A ECDSA signature.
* @throws "Invalid signature length" if the given signature has less than 65 bytes.
* @returns true if the v value is decimal 27 or 28 else otherwise.
*/
export function hasECDSASignatureAValidV(signature: string): boolean {
const lastSignatureByte = getLastECDSASignatureByte(signature)
return lastSignatureByte === 27 || lastSignatureByte === 28
}

/**
* Generates an ECDSA signature with a valid V from another signature by changing its V value to 27 or 28 if it was 0 or 1.
* @param signature - A ECDSA signature.
* @throws "Invalid signature length" if the given signature has less than 65 bytes.
* @returns a ECDSA signature based on the given one with its V value as 27 or 28.
*/
export function generateECDSASignatureWithValidV(signature: string): string {
const isSignatureVValid = hasECDSASignatureAValidV(signature)
return isSignatureVValid
? signature
: signature.slice(0, -2) + (getLastECDSASignatureByte(signature) + 27).toString(16)
}

/**
* Generates an ECDSA signature with an invalid V from another signature by changing its V value to 0 or 1 if it was 27 or 28.
* This function will be used to maintain support of signatures with a V of 0 and 1.
* @param signature - A ECDSA signature.
* @throws "Invalid signature length" if the given signature has less than 65 bytes.
* @returns a ECDSA signature based on the given one with its V value as 27 or 28.
*/
export function generateECDSASignatureWithInvalidV(signature: string): string {
const isSignatureVValid = hasECDSASignatureAValidV(signature)
return isSignatureVValid
? signature.slice(0, -2) + (getLastECDSASignatureByte(signature) - 27).toString(16)
: signature
}
Loading

0 comments on commit 5feee14

Please sign in to comment.