Skip to content

Commit

Permalink
Feat verify signature (#156)
Browse files Browse the repository at this point in the history
* feat: add signData feature to default account handler

* feat: add verifySignature feature to base account handler

* test: add unit test to signData

* test: add unit test to verifySignature
  • Loading branch information
fazzatti authored Jul 2, 2024
1 parent 0770e9a commit 9474d54
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 1 deletion.
14 changes: 14 additions & 0 deletions src/stellar-plus/account/account-handler/default/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export enum DefaultAccountHandlerErrorCodes {
DAH001 = 'DAH001',
DAH002 = 'DAH002',
DAH003 = 'DAH003',
DAH004 = 'DAH004',
}

const failedToLoadSecretKeyError = (error?: Error): StellarPlusError => {
Expand Down Expand Up @@ -55,8 +56,21 @@ const failedToSignAuthorizationEntryError = (
})
}

const failedToSignDataError = (error?: Error): StellarPlusError => {
return new StellarPlusError({
code: DefaultAccountHandlerErrorCodes.DAH004,
message: 'Failed to sign data!',
source: 'DefaultAccountHandler',
details: 'The data could not be signed. Review the secret key.',
meta: {
error,
},
})
}

export const DAHError = {
failedToLoadSecretKeyError,
failedToSignTransactionError,
failedToSignAuthorizationEntryError,
failedToSignDataError,
}
14 changes: 14 additions & 0 deletions src/stellar-plus/account/account-handler/default/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,18 @@ export class DefaultAccountHandlerClient extends AccountBase implements DefaultA
)
}
}

/**
*
* @param {Buffer} data - The data to sign.
* @returns {Buffer} The signature of the data.
*/
public signData(data: Buffer): Buffer {
try {
const keypair = Keypair.fromSecret(this.secretKey)
return keypair.sign(data)
} catch (e) {
throw DAHError.failedToSignDataError(e as Error)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ describe('DefaultAccountHandler', () => {
TESTNET_CONFIG.networkPassphrase
)
})

it('should sign data with its secret key', () => {
const keypair = Keypair.random()
const dah = new DefaultAccountHandlerClient({ networkConfig: TESTNET_CONFIG, secretKey: keypair.secret() })
const data = Buffer.from('Mocked Data')

const signature = dah.signData(data)

expect(dah.verifySignature(data, signature)).toBe(true)
})
})

describe('Getters', () => {
Expand Down Expand Up @@ -176,5 +186,14 @@ describe('DefaultAccountHandler', () => {
)
)
})

it('should throw an error if data cannot be signed', () => {
const keypair = Keypair.random()
const dah = new DefaultAccountHandlerClient({ networkConfig: TESTNET_CONFIG, secretKey: keypair.secret() })

expect(() => dah.signData(null as unknown as Buffer)).toThrow(
DAHError.failedToSignDataError(new Error('Mocked error'))
)
})
})
})
13 changes: 12 additions & 1 deletion src/stellar-plus/account/base/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Horizon } from '@stellar/stellar-sdk'
import { Horizon, Keypair } from '@stellar/stellar-sdk'
import axios from 'axios'

import { ABError } from 'stellar-plus/account/base/errors'
Expand Down Expand Up @@ -82,6 +82,17 @@ export class AccountBase implements AccountBaseType {
}
}

/**
*
* @param {Buffer} data - The data to sign.
* @param {Buffer} signature - The signature to verify.
* @returns {boolean} True if the signature is valid, false otherwise.
*/
public verifySignature(data: Buffer, signature: Buffer): boolean {
const keypair = Keypair.fromPublicKey(this.publicKey)
return keypair.verify(data, signature)
}

/**
*
* @description - Throws an error if the network is not a test network.
Expand Down
23 changes: 23 additions & 0 deletions src/stellar-plus/account/base/index.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { ABError } from 'stellar-plus/account/base/errors'
import { AxiosErrorTypes } from 'stellar-plus/error/helpers/axios'
import { HorizonHandler } from 'stellar-plus/horizon/types'
import { TestNet } from 'stellar-plus/network'
import { DefaultAccountHandlerClient } from '../account-handler/default'
import { Keypair } from '@stellar/stellar-sdk'

jest.mock('axios', () => {
const originalModule = jest.requireActual('axios')
Expand Down Expand Up @@ -94,6 +96,27 @@ describe('Base Account Handler', () => {
expect(balances).toBe(mockedBalances)
expect(mockedLoadAccount).toHaveBeenCalledExactlyOnceWith(MOCKED_PK)
})

it('verify if a signature is valid', () => {
const keypair = Keypair.random()
const dah = new DefaultAccountHandlerClient({ networkConfig: TESTNET_CONFIG, secretKey: keypair.secret() })
const data = Buffer.from('Mocked Data')

const signature = dah.signData(data)

expect(dah.verifySignature(data, signature)).toBe(true)
})

it('verify if a signature is not valid', () => {
const keypair = Keypair.random()
const dah = new DefaultAccountHandlerClient({ networkConfig: TESTNET_CONFIG, secretKey: keypair.secret() })
const secondDah = new DefaultAccountHandlerClient({ networkConfig: TESTNET_CONFIG })
const data = Buffer.from('Mocked Data')

const signature = dah.signData(data)

expect(secondDah.verifySignature(data, signature)).toBe(false)
})
})

describe('Error Handling', () => {
Expand Down

0 comments on commit 9474d54

Please sign in to comment.