@ngraveio/ur-sign
Version:
Provides BC-UR types for signature request and response from cold wallets to hot wallets.
152 lines (151 loc) • 7.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SignRequest = void 0;
const bc_ur_1 = require("@ngraveio/bc-ur");
const ur_blockchain_commons_1 = require("@ngraveio/ur-blockchain-commons");
const ur_uuid_1 = require("@ngraveio/ur-uuid");
const ur_coin_identity_1 = require("@ngraveio/ur-coin-identity");
class SignRequest extends (0, bc_ur_1.registryItemFactory)({
tag: 41411,
URType: 'sign-request',
allowKeysNotInMap: true,
keyMap: {
requestId: 1,
coinId: 2,
derivationPath: 3,
signData: 4,
origin: 5,
txType: 6,
address: 7,
},
CDDL: `
sign-request = {
?request-id: uuid, ; Identifier of the signing request
coin-id: #6.41401(coin-identity), ; Provides information on the elliptic curve and the blockchain/coin
?derivation-path: #6.40304(keypath), ; Key path for signing this request
sign-data: bytes, ; Transaction to be decoded by the offline signer
?origin: text, ; Origin of this sign request, e.g. wallet name
?tx-type: int .default 1 ; Specify type of transaction required for some blockchains
?address: string / bytes ; Specify sender address if not already specified in the sign-data and derivation-path
}
request-id = 1
coin-id = 2
derivation-path = 3
sign-data = 4
origin = 5
tx-type = 6
address=7
`,
}) {
constructor(data) {
super(data);
this.verifyInput = (input) => {
const reasons = [];
const response = () => ({ valid: reasons.length === 0, reasons: reasons.length > 0 ? reasons : undefined });
// If request id is provided check if it is a valid UUID
if (input.requestId !== undefined) {
try {
//@ts-ignore
new ur_uuid_1.UUID(input.requestId);
}
catch (error) {
reasons.push(new Error('Invalid requestId: ' + error.message));
}
}
// Check if coin id is provided
if (input.coinId == undefined || !(input.coinId instanceof ur_coin_identity_1.CoinIdentity)) {
reasons.push(new Error('Coin id is required and should be of type CoinIdentity'));
}
// If derivation path is provided it should be a valid string or instance of Keypath
if (input.derivationPath !== undefined) {
if (typeof input.derivationPath !== 'string' && !(input.derivationPath instanceof ur_blockchain_commons_1.Keypath)) {
reasons.push(new Error('Derivation path should be a string or instance of Keypath'));
return response();
}
// If derivation path is a string, try to create a Keypath instance
try {
const derivationPath = typeof input.derivationPath == 'string' ? new ur_blockchain_commons_1.Keypath({ path: input.derivationPath }) : input.derivationPath;
if (derivationPath.getComponents().length === 0) {
reasons.push(new Error('Derivation path should not be empty'));
}
if (!derivationPath.isOnlySimple()) {
reasons.push(new Error('Derivation path mush only contain simple index components'));
}
}
catch (error) {
reasons.push(new Error('Invalid derivation path: ' + error.toString()));
}
}
// Check if sign data is provided and is of type Buffer
if (input.signData === undefined || !(input.signData instanceof Uint8Array)) {
reasons.push(new Error('Sign data is required and should be of type Buffer'));
}
else {
if (input.signData.length === 0) {
reasons.push(new Error('Sign data should not be empty'));
}
}
// If origin is provided, it should be a string
if (input.origin !== undefined && typeof input.origin !== 'string') {
reasons.push(new Error('Origin should be a string'));
}
// If tx type is provided, it should be an positive integer
if (input.txType !== undefined && (!Number.isInteger(input.txType) || input.txType < 0)) {
reasons.push(new Error('Tx type should be a positive integer'));
}
// If address is provided, it should be a string or a buffer
if (input.address !== undefined && typeof input.address !== 'string' && !(input.address instanceof Uint8Array)) {
reasons.push(new Error('Address should be a string or a buffer'));
}
return response();
};
// Getters
this.getRequestId = () => this.data.requestId;
this.getCoinId = () => this.data.coinId;
this.getDerivationPath = () => this.data.derivationPath;
this.getSignData = () => this.data.signData;
this.getOrigin = () => this.data.origin;
this.getTxType = () => this.data.txType;
this.getAddress = () => {
if (this.data.address instanceof Uint8Array)
return Buffer.from(this.data.address).toString('hex');
return this.data.address;
};
// Verify input
const { valid, reasons } = this.verifyInput(data);
if (!valid) {
throw new Error(`#SignRequest Invalid input: ${reasons?.map(r => r.message).join(', ')}`);
}
//@ts-ignore
this.data = data;
// Convert signData to Buffer
if (!(data.signData instanceof Buffer)) {
this.data.signData = Buffer.from(data.signData);
}
// If no request id is provided, generate a random one
if (data.requestId === undefined) {
this.data.requestId = ur_uuid_1.UUID.generate();
}
else {
// Convert requestId to UUID if it is not already an instance of UUID
if (typeof data.requestId === 'string' || data.requestId instanceof Uint8Array) {
this.data.requestId = new ur_uuid_1.UUID(data.requestId);
}
else if (!(data.requestId instanceof ur_uuid_1.UUID)) {
throw new Error('Invalid requestId. Expected a UUID, string, or Uint8Array.');
}
}
// If given keypath is a string, convert it to Keypath
if (data.derivationPath !== undefined && typeof data.derivationPath === 'string') {
this.data.derivationPath = new ur_blockchain_commons_1.Keypath({ path: data.derivationPath });
}
// If coin is Ethereum and txType is not provided, set it to 1
if (data.coinId.getType() == 60) {
if (data.txType === undefined) {
this.data.txType = 1;
}
}
}
}
exports.SignRequest = SignRequest;
//# sourceMappingURL=SignRequest.js.map