Skip to content

Commit 6d023f7

Browse files
error validation for credentials actions
1 parent 263fce7 commit 6d023f7

File tree

5 files changed

+65
-11
lines changed

5 files changed

+65
-11
lines changed

packages/xrpl/src/models/transactions/CredentialAccept.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { BaseTransaction } from '../../../dist/npm'
22

3-
import { validateBaseTransaction } from './common'
3+
import { validateBaseTransaction, validateCredentialType } from './common'
4+
5+
/**
6+
* Credentials are represented in hex. Whilst they are allowed a maximum length of 64
7+
* bytes, every byte requires 2 hex characters for representation
8+
*/
49

510
/**
611
* accepts a credential issued to the Account (i.e. the Account is the Subject of the Credential object).
@@ -29,4 +34,6 @@ export interface CredentialAccept extends BaseTransaction {
2934
*/
3035
export function validateCredentialAccept(tx: Record<string, unknown>): void {
3136
validateBaseTransaction(tx)
37+
38+
validateCredentialType(tx.CredentialType)
3239
}

packages/xrpl/src/models/transactions/CredentialCreate.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { BaseTransaction } from '../../../dist/npm'
22

3-
import { validateBaseTransaction } from './common'
3+
import { validateBaseTransaction, validateCredentialType } from './common'
4+
5+
const MAX_URI_LENGTH = 256
46

57
/**
68
* Creates a Credential object. It must be sent by the issuer.
@@ -34,4 +36,8 @@ export interface CredentialCreate extends BaseTransaction {
3436
*/
3537
export function validateCredentialCreate(tx: Record<string, unknown>): void {
3638
validateBaseTransaction(tx)
39+
40+
validateURI(tx.URI)
41+
42+
validateCredentialType(tx.CredentialType)
3743
}

packages/xrpl/src/models/transactions/CredentialDelete.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { BaseTransaction } from '../../../dist/npm'
2+
import { ValidationError } from '../../errors'
23

3-
import { validateBaseTransaction } from './common'
4+
import { validateBaseTransaction, validateCredentialType } from './common'
45

56
/**
67
* Deletes a Credential object.
@@ -31,4 +32,12 @@ export interface CredentialDelete extends BaseTransaction {
3132
*/
3233
export function validateCredentialDelete(tx: Record<string, unknown>): void {
3334
validateBaseTransaction(tx)
34-
}
35+
36+
if (!tx.Account && !tx.Issuer) {
37+
throw new ValidationError(
38+
'CredentialDelete: Neither `issuer` nor `subject` was provided',
39+
)
40+
}
41+
42+
validateCredentialType(tx.CredentialType)
43+
}.

packages/xrpl/src/models/transactions/common.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { HEX_REGEX } from '@xrplf/isomorphic/dist/utils'
12
import { isValidClassicAddress, isValidXAddress } from 'ripple-address-codec'
23
import { TRANSACTION_TYPES } from 'ripple-binary-codec'
34

@@ -366,3 +367,28 @@ export function parseAmountValue(amount: unknown): number {
366367
}
367368
return parseFloat(amount.value)
368369
}
370+
371+
const MAX_CREDENTIAL_TYPE_LENGTH = 64 * 2
372+
/**
373+
* Check a CredentialType for formatting errors
374+
*
375+
* @param credentialType A credential type field to check for errors
376+
* @throws Validation Error if the formatting is incorrect
377+
*/
378+
export function validateCredentialType(credentialType: string): void {
379+
if (credentialType.length === 0) {
380+
throw new ValidationError(
381+
'CredentialAccept: CredentialType length must be > 0.',
382+
)
383+
} else if (credentialType.length > MAX_CREDENTIAL_TYPE_LENGTH) {
384+
throw new ValidationError(
385+
`CredentialAccept: CredentialType length sust be < ${MAX_CREDENTIAL_TYPE_LENGTH}.`,
386+
)
387+
}
388+
389+
if (!HEX_REGEX.test(credentialType)) {
390+
throw new ValidationError(
391+
`CredentialAccept: CredentialType myust be encoded in hex.`,
392+
)
393+
}
394+
}

packages/xrpl/src/models/transactions/depositPreauth.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,19 @@ export interface DepositPreauth extends BaseTransaction {
3434
export function validateDepositPreauth(tx: Record<string, unknown>): void {
3535
validateBaseTransaction(tx)
3636

37-
if (tx.Authorize !== undefined && tx.Unauthorize !== undefined) {
38-
throw new ValidationError(
39-
"DepositPreauth: can't provide both Authorize and Unauthorize fields",
40-
)
41-
}
37+
// Boolean logic to ensure exactly one of 4 inputs was provided
38+
const normalAuthorizeXOR = !tx.Authorize !== !tx.Unauthorize
39+
const authorizeCredentialsXOR =
40+
!tx.AuthorizeCredentials !== !tx.UnauthorizeCredentials
4241

43-
if (tx.Authorize === undefined && tx.Unauthorize === undefined) {
42+
if (normalAuthorizeXOR === authorizeCredentialsXOR) {
4443
throw new ValidationError(
45-
'DepositPreauth: must provide either Authorize or Unauthorize field',
44+
'DepositPreauth txn requires exactly one input amongst authorize, unauthorize, authorize_credentials and unauthorize_credentials.',
4645
)
4746
}
4847

4948
if (tx.Authorize !== undefined) {
49+
// is this needed
5050
if (typeof tx.Authorize !== 'string') {
5151
throw new ValidationError('DepositPreauth: Authorize must be a string')
5252
}
@@ -58,6 +58,12 @@ export function validateDepositPreauth(tx: Record<string, unknown>): void {
5858
}
5959
}
6060

61+
if (tx.AuthorizeCredentials) {
62+
validateCredentialsList(tx.AuthorizeCredentials)
63+
} else if (tx.UnauthorizeCredentials) {
64+
validateCredentialsList(tx.UnauthorizeCredentials)
65+
}
66+
6167
if (tx.Unauthorize !== undefined) {
6268
if (typeof tx.Unauthorize !== 'string') {
6369
throw new ValidationError('DepositPreauth: Unauthorize must be a string')

0 commit comments

Comments
 (0)