mirror of
https://github.com/Xahau/xahau.js.git
synced 2026-06-04 17:26:46 +00:00
address codec linting (#1881)
This commit is contained in:
@@ -33,18 +33,7 @@ module.exports = {
|
||||
// all of the below are turned off for now during the migration to a
|
||||
// monorepo. They need to actually be addressed!
|
||||
// **
|
||||
'@typescript-eslint/consistent-type-assertions': 'off',
|
||||
'@typescript-eslint/no-unnecessary-condition': 'off',
|
||||
'@typescript-eslint/no-unsafe-call': 'off',
|
||||
'@typescript-eslint/no-magic-numbers': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/no-unsafe-return': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/explicit-member-accessibility': 'off',
|
||||
'@typescript-eslint/promise-function-async': 'off',
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 'off',
|
||||
'@typescript-eslint/naming-convention': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'jsdoc/require-returns': 'off',
|
||||
'jsdoc/check-param-names': 'off',
|
||||
'jsdoc/require-throws': 'off',
|
||||
|
||||
@@ -15,9 +15,9 @@ import {
|
||||
|
||||
const PREFIX_BYTES = {
|
||||
// 5, 68
|
||||
MAIN: Buffer.from([0x05, 0x44]),
|
||||
main: Buffer.from([0x05, 0x44]),
|
||||
// 4, 147
|
||||
TEST: Buffer.from([0x04, 0x93]),
|
||||
test: Buffer.from([0x04, 0x93]),
|
||||
}
|
||||
|
||||
const MAX_32_BIT_UNSIGNED_INT = 4294967295
|
||||
@@ -48,7 +48,7 @@ function encodeXAddress(
|
||||
/* eslint-disable no-bitwise ---
|
||||
* need to use bitwise operations here */
|
||||
const bytes = Buffer.concat([
|
||||
test ? PREFIX_BYTES.TEST : PREFIX_BYTES.MAIN,
|
||||
test ? PREFIX_BYTES.test : PREFIX_BYTES.main,
|
||||
accountId,
|
||||
Buffer.from([
|
||||
// 0x00 if no tag, 0x01 if 32-bit tag
|
||||
@@ -77,7 +77,11 @@ function xAddressToClassicAddress(xAddress: string): {
|
||||
tag: number | false
|
||||
test: boolean
|
||||
} {
|
||||
/* eslint-disable @typescript-eslint/naming-convention --
|
||||
* TODO 'test' should be something like 'isTest', do this later
|
||||
*/
|
||||
const { accountId, tag, test } = decodeXAddress(xAddress)
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
const classicAddress = encodeAccountID(accountId)
|
||||
return {
|
||||
classicAddress,
|
||||
@@ -92,7 +96,11 @@ function decodeXAddress(xAddress: string): {
|
||||
test: boolean
|
||||
} {
|
||||
const decoded = codec.decodeChecked(xAddress)
|
||||
/* eslint-disable @typescript-eslint/naming-convention --
|
||||
* TODO 'test' should be something like 'isTest', do this later
|
||||
*/
|
||||
const test = isBufferForTestAddress(decoded)
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
const accountId = decoded.slice(2, 22)
|
||||
const tag = tagFromBuffer(decoded)
|
||||
return {
|
||||
@@ -104,10 +112,10 @@ function decodeXAddress(xAddress: string): {
|
||||
|
||||
function isBufferForTestAddress(buf: Buffer): boolean {
|
||||
const decodedPrefix = buf.slice(0, 2)
|
||||
if (PREFIX_BYTES.MAIN.equals(decodedPrefix)) {
|
||||
if (PREFIX_BYTES.main.equals(decodedPrefix)) {
|
||||
return false
|
||||
}
|
||||
if (PREFIX_BYTES.TEST.equals(decodedPrefix)) {
|
||||
if (PREFIX_BYTES.test.equals(decodedPrefix)) {
|
||||
return true
|
||||
}
|
||||
throw new Error('Invalid X-address: bad prefix')
|
||||
|
||||
@@ -25,7 +25,7 @@ export function seqEqual(arr1: Sequence, arr2: Sequence): boolean {
|
||||
* @param val - The value to check.
|
||||
*/
|
||||
function isSequence(val: Sequence | number): val is Sequence {
|
||||
return (val as Sequence).length !== undefined
|
||||
return typeof val !== 'number'
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,6 +36,7 @@ function isSequence(val: Sequence | number): val is Sequence {
|
||||
* > concatArgs(1, [2, 3], Buffer.from([4,5]), new Uint8Array([6, 7]));
|
||||
* [1,2,3,4,5,6,7]
|
||||
*
|
||||
* @param args - Concatenate of these args into a single array.
|
||||
* @returns Array of concatenated arguments
|
||||
*/
|
||||
export function concatArgs(...args: Array<number | Sequence>): number[] {
|
||||
|
||||
@@ -8,19 +8,17 @@ import * as createHash from 'create-hash'
|
||||
import { seqEqual, concatArgs } from './utils'
|
||||
|
||||
class Codec {
|
||||
sha256: (bytes: Uint8Array) => Buffer
|
||||
alphabet: string
|
||||
codec: baseCodec.BaseConverter
|
||||
base: number
|
||||
private readonly _sha256: (bytes: Uint8Array) => Buffer
|
||||
private readonly _alphabet: string
|
||||
private readonly _codec: baseCodec.BaseConverter
|
||||
|
||||
constructor(options: {
|
||||
public constructor(options: {
|
||||
sha256: (bytes: Uint8Array) => Buffer
|
||||
alphabet: string
|
||||
}) {
|
||||
this.sha256 = options.sha256
|
||||
this.alphabet = options.alphabet
|
||||
this.codec = baseCodec(this.alphabet)
|
||||
this.base = this.alphabet.length
|
||||
this._sha256 = options.sha256
|
||||
this._alphabet = options.alphabet
|
||||
this._codec = baseCodec(this._alphabet)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,7 +27,7 @@ class Codec {
|
||||
* @param bytes - Buffer of data to encode.
|
||||
* @param opts - Options object including the version bytes and the expected length of the data to encode.
|
||||
*/
|
||||
encode(
|
||||
public encode(
|
||||
bytes: Buffer,
|
||||
opts: {
|
||||
versions: number[]
|
||||
@@ -37,30 +35,7 @@ class Codec {
|
||||
},
|
||||
): string {
|
||||
const versions = opts.versions
|
||||
return this.encodeVersioned(bytes, versions, opts.expectedLength)
|
||||
}
|
||||
|
||||
encodeVersioned(
|
||||
bytes: Buffer,
|
||||
versions: number[],
|
||||
expectedLength: number,
|
||||
): string {
|
||||
if (expectedLength && bytes.length !== expectedLength) {
|
||||
throw new Error(
|
||||
'unexpected_payload_length: bytes.length does not match expectedLength.' +
|
||||
' Ensure that the bytes are a Buffer.',
|
||||
)
|
||||
}
|
||||
return this.encodeChecked(Buffer.from(concatArgs(versions, bytes)))
|
||||
}
|
||||
|
||||
encodeChecked(buffer: Buffer): string {
|
||||
const check = this.sha256(this.sha256(buffer)).slice(0, 4)
|
||||
return this.encodeRaw(Buffer.from(concatArgs(buffer, check)))
|
||||
}
|
||||
|
||||
encodeRaw(bytes: Buffer): string {
|
||||
return this.codec.encode(bytes)
|
||||
return this._encodeVersioned(bytes, versions, opts.expectedLength)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,7 +46,7 @@ class Codec {
|
||||
*/
|
||||
/* eslint-disable max-lines-per-function --
|
||||
* TODO refactor */
|
||||
decode(
|
||||
public decode(
|
||||
base58string: string,
|
||||
opts: {
|
||||
versions: Array<number | number[]>
|
||||
@@ -96,11 +71,13 @@ class Codec {
|
||||
const versionLengthGuess =
|
||||
typeof versions[0] === 'number' ? 1 : versions[0].length
|
||||
const payloadLength =
|
||||
opts.expectedLength || withoutSum.length - versionLengthGuess
|
||||
opts.expectedLength ?? withoutSum.length - versionLengthGuess
|
||||
const versionBytes = withoutSum.slice(0, -payloadLength)
|
||||
const payload = withoutSum.slice(-payloadLength)
|
||||
|
||||
for (let i = 0; i < versions.length; i++) {
|
||||
/* eslint-disable @typescript-eslint/consistent-type-assertions --
|
||||
* TODO refactor */
|
||||
const version: number[] = Array.isArray(versions[i])
|
||||
? (versions[i] as number[])
|
||||
: [versions[i] as number]
|
||||
@@ -111,31 +88,55 @@ class Codec {
|
||||
type: types ? types[i] : null,
|
||||
}
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/consistent-type-assertions */
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
'version_invalid: version bytes do not match any of the provided version(s)',
|
||||
)
|
||||
}
|
||||
/* eslint-enable max-lines-per-function */
|
||||
|
||||
decodeChecked(base58string: string): Buffer {
|
||||
const buffer = this.decodeRaw(base58string)
|
||||
public encodeChecked(buffer: Buffer): string {
|
||||
const check = this._sha256(this._sha256(buffer)).slice(0, 4)
|
||||
return this._encodeRaw(Buffer.from(concatArgs(buffer, check)))
|
||||
}
|
||||
|
||||
public decodeChecked(base58string: string): Buffer {
|
||||
const buffer = this._decodeRaw(base58string)
|
||||
if (buffer.length < 5) {
|
||||
throw new Error('invalid_input_size: decoded data must have length >= 5')
|
||||
}
|
||||
if (!this.verifyCheckSum(buffer)) {
|
||||
if (!this._verifyCheckSum(buffer)) {
|
||||
throw new Error('checksum_invalid')
|
||||
}
|
||||
return buffer.slice(0, -4)
|
||||
}
|
||||
|
||||
decodeRaw(base58string: string): Buffer {
|
||||
return this.codec.decode(base58string)
|
||||
private _encodeVersioned(
|
||||
bytes: Buffer,
|
||||
versions: number[],
|
||||
expectedLength: number,
|
||||
): string {
|
||||
if (expectedLength && bytes.length !== expectedLength) {
|
||||
throw new Error(
|
||||
'unexpected_payload_length: bytes.length does not match expectedLength.' +
|
||||
' Ensure that the bytes are a Buffer.',
|
||||
)
|
||||
}
|
||||
return this.encodeChecked(Buffer.from(concatArgs(versions, bytes)))
|
||||
}
|
||||
|
||||
verifyCheckSum(bytes: Buffer): boolean {
|
||||
const computed = this.sha256(this.sha256(bytes.slice(0, -4))).slice(0, 4)
|
||||
private _encodeRaw(bytes: Buffer): string {
|
||||
return this._codec.encode(bytes)
|
||||
}
|
||||
/* eslint-enable max-lines-per-function */
|
||||
|
||||
private _decodeRaw(base58string: string): Buffer {
|
||||
return this._codec.decode(base58string)
|
||||
}
|
||||
|
||||
private _verifyCheckSum(bytes: Buffer): boolean {
|
||||
const computed = this._sha256(this._sha256(bytes.slice(0, -4))).slice(0, 4)
|
||||
const checksum = bytes.slice(-4)
|
||||
return seqEqual(computed, checksum)
|
||||
}
|
||||
@@ -159,7 +160,7 @@ const NODE_PUBLIC = 0x1c
|
||||
const ED25519_SEED = [0x01, 0xe1, 0x4b]
|
||||
|
||||
const codecOptions = {
|
||||
sha256(bytes: Uint8Array) {
|
||||
sha256(bytes: Uint8Array): Buffer {
|
||||
return createHash('sha256').update(Buffer.from(bytes)).digest()
|
||||
},
|
||||
alphabet: 'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz',
|
||||
@@ -200,7 +201,11 @@ export function decodeSeed(
|
||||
versions: [ED25519_SEED, FAMILY_SEED],
|
||||
expectedLength: 16,
|
||||
},
|
||||
) {
|
||||
): {
|
||||
version: number[]
|
||||
bytes: Buffer
|
||||
type: string | null
|
||||
} {
|
||||
return codecWithXrpAlphabet.decode(seed, opts)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user