chore(lint): apply prettier to secret-numbers (#2549)

The config was not applied when it was moved to the monorepo
This commit is contained in:
Caleb Kniffen
2023-10-25 17:35:11 -05:00
parent c5fc25efc2
commit fa4eabef0e
7 changed files with 244 additions and 247 deletions

View File

@@ -4,12 +4,12 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr
## 1.0.0 Beta 1 (2023-10-19)
- Add `xrpl-secret-numbers` by @WietseWind to the mono repo.
- `unpkg` and `jsdelivr` support was simplified.
- Unit tests run in a browser and node.
- Remove `brorand` as a dependency and use `@xrplf/isomorphic` instead.
* Add `xrpl-secret-numbers` by @WietseWind to the mono repo.
* `unpkg` and `jsdelivr` support was simplified.
* Unit tests run in a browser and node.
* Remove `brorand` as a dependency and use `@xrplf/isomorphic` instead.
### BREAKING CHANGES:
- `xrpl-secret-numbers` is now `@xrplf/secret-numbers`.
- The bundled file produced changed from `dist/browerified.js` to `build/xrplf-secret-numbers-latest.js`.
- Bundle variable is `xrplf_secret_numbers` instead of using browserify's loader.
* `xrpl-secret-numbers` is now `@xrplf/secret-numbers`.
* The bundled file produced changed from `dist/browerified.js` to `build/xrplf-secret-numbers-latest.js`.
* Bundle variable is `xrplf_secret_numbers` instead of using browserify's loader.

View File

@@ -32,6 +32,7 @@
"@xrplf/isomorphic": "^1.0.0-beta.0",
"ripple-keypairs": "^2.0.0-beta.0"
},
"prettier": "@xrplf/prettier-config",
"repository": {
"type": "git",
"url": "git@github.com:XRPLF/xrpl.js.git"

View File

@@ -1,8 +1,8 @@
/* Methods ==================================================================== */
import Account from "./schema/Account";
import * as Utils from "./utils";
import Account from './schema/Account'
import * as Utils from './utils'
/* Types ==================================================================== */
/* Export ==================================================================== */
export { Account, Utils };
export { Account, Utils }

View File

@@ -1,99 +1,99 @@
import * as keypairs from "ripple-keypairs";
import * as keypairs from 'ripple-keypairs'
import * as utils from "../utils";
import * as utils from '../utils'
/* Types ==================================================================== */
// eslint-disable-next-line import/no-unused-modules -- it is returned by Account.getKeypair
export interface Keypair {
publicKey: string;
privateKey: string;
publicKey: string
privateKey: string
}
interface AccountData {
familySeed: string;
address: string;
keypair: Keypair;
familySeed: string
address: string
keypair: Keypair
}
/* Class ==================================================================== */
export default class Account {
private readonly _secret: string[];
private readonly _secret: string[]
private readonly _account: AccountData = {
familySeed: "",
address: "",
familySeed: '',
address: '',
keypair: {
publicKey: "",
privateKey: "",
publicKey: '',
privateKey: '',
},
};
constructor(secretNumbers?: string[] | string | Buffer) {
if (typeof secretNumbers === "string") {
this._secret = utils.parseSecretString(secretNumbers);
} else if (Array.isArray(secretNumbers)) {
this._secret = secretNumbers;
} else if (Buffer.isBuffer(secretNumbers)) {
this._secret = utils.entropyToSecret(secretNumbers);
} else {
this._secret = utils.randomSecret();
}
validateLengths(this._secret);
this.derive();
constructor(secretNumbers?: string[] | string | Buffer) {
if (typeof secretNumbers === 'string') {
this._secret = utils.parseSecretString(secretNumbers)
} else if (Array.isArray(secretNumbers)) {
this._secret = secretNumbers
} else if (Buffer.isBuffer(secretNumbers)) {
this._secret = utils.entropyToSecret(secretNumbers)
} else {
this._secret = utils.randomSecret()
}
validateLengths(this._secret)
this.derive()
}
getSecret(): string[] {
return this._secret;
return this._secret
}
getSecretString(): string {
return this._secret.join(" ");
return this._secret.join(' ')
}
getAddress(): string {
return this._account.address;
return this._account.address
}
getFamilySeed(): string {
return this._account.familySeed;
return this._account.familySeed
}
getKeypair(): Keypair {
return this._account.keypair;
return this._account.keypair
}
toString(): string {
return this.getSecretString();
return this.getSecretString()
}
private derive(): void {
try {
const entropy = utils.secretToEntropy(this._secret);
this._account.familySeed = keypairs.generateSeed({ entropy });
this._account.keypair = keypairs.deriveKeypair(this._account.familySeed);
const entropy = utils.secretToEntropy(this._secret)
this._account.familySeed = keypairs.generateSeed({ entropy })
this._account.keypair = keypairs.deriveKeypair(this._account.familySeed)
this._account.address = keypairs.deriveAddress(
this._account.keypair.publicKey
);
this._account.keypair.publicKey,
)
} catch (error) {
let message = "Unknown Error";
let message = 'Unknown Error'
if (error instanceof Error) {
message = error.message;
message = error.message
}
// we'll proceed, but let's report it
throw new Error(message);
throw new Error(message)
}
}
}
function validateLengths(secretNumbers: string[]): void {
if (secretNumbers.length !== 8) {
throw new Error("Secret must have 8 numbers");
throw new Error('Secret must have 8 numbers')
}
secretNumbers.forEach((num) => {
if (num.length !== 6) {
throw new Error("Each secret number must be 6 digits");
throw new Error('Each secret number must be 6 digits')
}
});
})
}

View File

@@ -1,82 +1,82 @@
import { randomBytes } from "@xrplf/isomorphic/utils";
import { randomBytes } from '@xrplf/isomorphic/utils'
function randomEntropy(): Buffer {
return Buffer.from(randomBytes(16));
return Buffer.from(randomBytes(16))
}
function calculateChecksum(position: number, value: number): number {
return (value * (position * 2 + 1)) % 9;
return (value * (position * 2 + 1)) % 9
}
function checkChecksum(
position: number,
value: number | string,
checksum?: number
checksum?: number,
): boolean {
let normalizedChecksum: number;
let normalizedValue: number;
let normalizedChecksum: number
let normalizedValue: number
if (typeof value === "string") {
if (typeof value === 'string') {
if (value.length !== 6) {
throw new Error("value must have a length of 6");
throw new Error('value must have a length of 6')
}
normalizedChecksum = parseInt(value.slice(5), 10);
normalizedValue = parseInt(value.slice(0, 5), 10);
normalizedChecksum = parseInt(value.slice(5), 10)
normalizedValue = parseInt(value.slice(0, 5), 10)
} else {
if (typeof checksum !== "number") {
throw new Error("checksum must be a number when value is a number");
if (typeof checksum !== 'number') {
throw new Error('checksum must be a number when value is a number')
}
normalizedChecksum = checksum;
normalizedValue = value;
normalizedChecksum = checksum
normalizedValue = value
}
return (normalizedValue * (position * 2 + 1)) % 9 === normalizedChecksum;
return (normalizedValue * (position * 2 + 1)) % 9 === normalizedChecksum
}
function entropyToSecret(entropy: Buffer): string[] {
const len = new Array(Math.ceil(entropy.length / 2));
const len = new Array(Math.ceil(entropy.length / 2))
const chunks = Array.from(len, (_a, chunk) => {
const buffChunk = entropy.slice(chunk * 2, (chunk + 1) * 2);
const no = parseInt(buffChunk.toString("hex"), 16);
const fill = "0".repeat(5 - String(no).length);
return fill + String(no) + String(calculateChecksum(chunk, no));
});
const buffChunk = entropy.slice(chunk * 2, (chunk + 1) * 2)
const no = parseInt(buffChunk.toString('hex'), 16)
const fill = '0'.repeat(5 - String(no).length)
return fill + String(no) + String(calculateChecksum(chunk, no))
})
if (chunks.length !== 8) {
throw new Error("Chucks must have 8 digits");
throw new Error('Chucks must have 8 digits')
}
return chunks;
return chunks
}
function randomSecret(): string[] {
return entropyToSecret(randomEntropy());
return entropyToSecret(randomEntropy())
}
function secretToEntropy(secret: string[]): Buffer {
return Buffer.concat(
secret.map((chunk, i) => {
const no = Number(chunk.slice(0, 5));
const checksum = Number(chunk.slice(5));
const no = Number(chunk.slice(0, 5))
const checksum = Number(chunk.slice(5))
if (chunk.length !== 6) {
throw new Error("Invalid secret: number invalid");
throw new Error('Invalid secret: number invalid')
}
if (!checkChecksum(i, no, checksum)) {
throw new Error("Invalid secret part: checksum invalid");
throw new Error('Invalid secret part: checksum invalid')
}
const hex = `0000${no.toString(16)}`.slice(-4);
return Buffer.from(hex, "hex");
})
);
const hex = `0000${no.toString(16)}`.slice(-4)
return Buffer.from(hex, 'hex')
}),
)
}
function parseSecretString(secret: string): string[] {
const normalizedSecret = secret.replace(/[^0-9]/gu, "");
const normalizedSecret = secret.replace(/[^0-9]/gu, '')
if (normalizedSecret.length !== 48) {
throw new Error(
"Invalid secret string (should contain 8 blocks of 6 digits"
);
'Invalid secret string (should contain 8 blocks of 6 digits',
)
}
return Array.from(new Array(8), (_a, index) => {
return normalizedSecret.slice(index * 6, (index + 1) * 6);
});
return normalizedSecret.slice(index * 6, (index + 1) * 6)
})
}
export {
@@ -87,4 +87,4 @@ export {
calculateChecksum,
checkChecksum,
parseSecretString,
};
}

View File

@@ -1,99 +1,95 @@
import * as keypairs from "ripple-keypairs";
import * as keypairs from 'ripple-keypairs'
import { Account, Utils } from "../src";
import { Account, Utils } from '../src'
describe("API: XRPL Secret Numbers", () => {
describe("Generate new account", () => {
const account = new Account();
it("Output sanity checks", () => {
expect(account.getAddress()).toMatch(/^r[a-zA-Z0-9]{19,}$/u);
const entropy = Utils.secretToEntropy(`${account.toString()}`.split(" "));
const familySeed = keypairs.generateSeed({ entropy });
const keypair = keypairs.deriveKeypair(familySeed);
const address = keypairs.deriveAddress(keypair.publicKey);
expect(address).toEqual(account.getAddress());
expect(familySeed).toEqual(account.getFamilySeed());
});
});
describe('API: XRPL Secret Numbers', () => {
describe('Generate new account', () => {
const account = new Account()
it('Output sanity checks', () => {
expect(account.getAddress()).toMatch(/^r[a-zA-Z0-9]{19,}$/u)
const entropy = Utils.secretToEntropy(`${account.toString()}`.split(' '))
const familySeed = keypairs.generateSeed({ entropy })
const keypair = keypairs.deriveKeypair(familySeed)
const address = keypairs.deriveAddress(keypair.publicKey)
expect(address).toEqual(account.getAddress())
expect(familySeed).toEqual(account.getFamilySeed())
})
})
describe("Account based on entropy", () => {
const entropy = Buffer.from("0123456789ABCDEF0123456789ABCDEF", "hex");
const account = new Account(entropy);
describe('Account based on entropy', () => {
const entropy = Buffer.from('0123456789ABCDEF0123456789ABCDEF', 'hex')
const account = new Account(entropy)
it("familySeed as expected", () => {
expect(account.getFamilySeed()).toEqual("sp5DmDCut79BpgumfHhvRzdxXYQyU");
});
it("address as expected", () => {
expect(account.getAddress()).toEqual(
"rMCcybKHfwCSkDHd3M36PAeUniEoygwjR3"
);
});
it("Account object to string as expected", () => {
it('familySeed as expected', () => {
expect(account.getFamilySeed()).toEqual('sp5DmDCut79BpgumfHhvRzdxXYQyU')
})
it('address as expected', () => {
expect(account.getAddress()).toEqual('rMCcybKHfwCSkDHd3M36PAeUniEoygwjR3')
})
it('Account object to string as expected', () => {
const accountAsStr =
"002913 177673 352434 527196 002910 177672 352435 527190";
expect(`${account.toString()}`).toEqual(accountAsStr);
});
});
'002913 177673 352434 527196 002910 177672 352435 527190'
expect(`${account.toString()}`).toEqual(accountAsStr)
})
})
describe("Account based on existing secret", () => {
describe('Account based on existing secret', () => {
const secret = [
"084677",
"005323",
"580272",
"282388",
"626800",
"105300",
"560913",
"071783",
];
'084677',
'005323',
'580272',
'282388',
'626800',
'105300',
'560913',
'071783',
]
const account = new Account(secret);
const account = new Account(secret)
it("familySeed as expected", () => {
expect(account.getFamilySeed()).toEqual("sswpWwri7Y11dNCSmXdphgcoPZk3y");
});
it("publicKey as expected", () => {
it('familySeed as expected', () => {
expect(account.getFamilySeed()).toEqual('sswpWwri7Y11dNCSmXdphgcoPZk3y')
})
it('publicKey as expected', () => {
const pubkey =
"020526A0EDC9123F7FBB7588402518B80FCD2C8D8AB4C45F5A68A2F220098EA06F";
expect(account.getKeypair().publicKey).toEqual(pubkey);
});
it("privateKey as expected", () => {
'020526A0EDC9123F7FBB7588402518B80FCD2C8D8AB4C45F5A68A2F220098EA06F'
expect(account.getKeypair().publicKey).toEqual(pubkey)
})
it('privateKey as expected', () => {
const privkey =
"005122B2127B4635FEE7D242FA6EC9B02B611C04494D0D7D49764374D90C8BC8D3";
expect(account.getKeypair().privateKey).toEqual(privkey);
});
it("address as expected", () => {
expect(account.getAddress()).toEqual(
"rfqJsRLLmr7wdWnEzW1mP6AVaPSdzmso9Z"
);
});
it("Account object to string as expected", () => {
'005122B2127B4635FEE7D242FA6EC9B02B611C04494D0D7D49764374D90C8BC8D3'
expect(account.getKeypair().privateKey).toEqual(privkey)
})
it('address as expected', () => {
expect(account.getAddress()).toEqual('rfqJsRLLmr7wdWnEzW1mP6AVaPSdzmso9Z')
})
it('Account object to string as expected', () => {
const accountAsStr =
"084677 005323 580272 282388 626800 105300 560913 071783";
expect(`${account.toString()}`).toEqual(accountAsStr);
});
});
'084677 005323 580272 282388 626800 105300 560913 071783'
expect(`${account.toString()}`).toEqual(accountAsStr)
})
})
describe("Checksum error", () => {
describe('Checksum error', () => {
const secret = [
"084677",
"005324",
"580272",
"626800",
"282388",
"105300",
"560913",
"071783",
];
it("Should throw an Checksum Error", () => {
'084677',
'005324',
'580272',
'626800',
'282388',
'105300',
'560913',
'071783',
]
it('Should throw an Checksum Error', () => {
expect(() => {
// eslint-disable-next-line no-new -- Don't want unused variable
new Account(secret);
new Account(secret)
})
// TODO: Remove if jest is removed.
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- Jest and Jasmine have two different signatures.
// @ts-expect-error
.toThrowError(Error, "Invalid secret part: checksum invalid");
});
});
});
.toThrowError(Error, 'Invalid secret part: checksum invalid')
})
})
})

View File

@@ -1,107 +1,107 @@
import * as utils from "../src/utils";
import * as utils from '../src/utils'
describe("Utils", () => {
it("randomEntropy: valid output", () => {
const data = utils.randomEntropy();
expect(typeof data).toEqual("object");
expect(data instanceof Buffer).toBeTruthy();
expect(data.length).toEqual(16);
expect(data.toString("hex").length).toEqual(32);
expect(data.toString("hex")).toMatch(/^[a-f0-9]+$/u);
});
describe('Utils', () => {
it('randomEntropy: valid output', () => {
const data = utils.randomEntropy()
expect(typeof data).toEqual('object')
expect(data instanceof Buffer).toBeTruthy()
expect(data.length).toEqual(16)
expect(data.toString('hex').length).toEqual(32)
expect(data.toString('hex')).toMatch(/^[a-f0-9]+$/u)
})
it("calculateChecksum: 1st position", () => {
expect(utils.calculateChecksum(0, 55988)).toEqual(8);
});
it('calculateChecksum: 1st position', () => {
expect(utils.calculateChecksum(0, 55988)).toEqual(8)
})
it("calculateChecksum: 8th position", () => {
expect(utils.calculateChecksum(7, 49962)).toEqual(0);
});
it('calculateChecksum: 8th position', () => {
expect(utils.calculateChecksum(7, 49962)).toEqual(0)
})
it("checkChecksum: 2nd position, split numbers", () => {
expect(utils.checkChecksum(1, 55450, 3)).toBeTruthy();
});
it('checkChecksum: 2nd position, split numbers', () => {
expect(utils.checkChecksum(1, 55450, 3)).toBeTruthy()
})
it("checkChecksum: 7th position, split numbers", () => {
expect(utils.checkChecksum(6, 18373, 7)).toBeTruthy();
});
it('checkChecksum: 7th position, split numbers', () => {
expect(utils.checkChecksum(6, 18373, 7)).toBeTruthy()
})
it("checkChecksum: 4th position, as string", () => {
expect(utils.checkChecksum(3, "391566")).toBeTruthy();
});
it('checkChecksum: 4th position, as string', () => {
expect(utils.checkChecksum(3, '391566')).toBeTruthy()
})
it("randomSecret: valid checksums", () => {
utils.randomSecret();
expect(0).toEqual(0);
});
it('randomSecret: valid checksums', () => {
utils.randomSecret()
expect(0).toEqual(0)
})
it("randomSecret: valid output", () => {
const data = utils.randomSecret();
expect(Array.isArray(data)).toBeTruthy();
expect(data.length).toEqual(8);
expect(typeof data[0]).toEqual("string");
expect(data[0].length).toEqual(6);
expect(data[7].length).toEqual(6);
});
it('randomSecret: valid output', () => {
const data = utils.randomSecret()
expect(Array.isArray(data)).toBeTruthy()
expect(data.length).toEqual(8)
expect(typeof data[0]).toEqual('string')
expect(data[0].length).toEqual(6)
expect(data[7].length).toEqual(6)
})
it("entropyToSecret", () => {
const entropy = Buffer.from("76ebb2d06879b45b7568fb9c1ded097c", "hex");
it('entropyToSecret', () => {
const entropy = Buffer.from('76ebb2d06879b45b7568fb9c1ded097c', 'hex')
const secret = [
"304435",
"457766",
"267453",
"461717",
"300560",
"644127",
"076618",
"024286",
];
expect(utils.entropyToSecret(entropy)).toEqual(secret);
});
'304435',
'457766',
'267453',
'461717',
'300560',
'644127',
'076618',
'024286',
]
expect(utils.entropyToSecret(entropy)).toEqual(secret)
})
it("secretToEntropy", () => {
it('secretToEntropy', () => {
const secret = [
"304435",
"457766",
"267453",
"461717",
"300560",
"644127",
"076618",
"024286",
];
const entropy = Buffer.from("76ebb2d06879b45b7568fb9c1ded097c", "hex");
expect(utils.secretToEntropy(secret)).toEqual(entropy);
});
'304435',
'457766',
'267453',
'461717',
'300560',
'644127',
'076618',
'024286',
]
const entropy = Buffer.from('76ebb2d06879b45b7568fb9c1ded097c', 'hex')
expect(utils.secretToEntropy(secret)).toEqual(entropy)
})
it("parseSecretString with spaces valid", () => {
it('parseSecretString with spaces valid', () => {
const secret = [
"304435",
"457766",
"267453",
"461717",
"300560",
"644127",
"076618",
"024286",
];
'304435',
'457766',
'267453',
'461717',
'300560',
'644127',
'076618',
'024286',
]
expect(
utils.parseSecretString(
"304435 457766 267453 461717 300560 644127 076618 024286"
)
).toEqual(secret);
'304435 457766 267453 461717 300560 644127 076618 024286',
),
).toEqual(secret)
expect(
utils.parseSecretString(
"304435457766267453461717300560644127076618024286"
)
).toEqual(secret);
'304435457766267453461717300560644127076618024286',
),
).toEqual(secret)
expect(
utils.parseSecretString(`
304435 457766
267453 461717
300560 644127
076618 024286
`)
).toEqual(secret);
});
});
`),
).toEqual(secret)
})
})