New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@canvas-js/chain-cosmos

Package Overview
Dependencies
Maintainers
3
Versions
173
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@canvas-js/chain-cosmos - npm Package Compare versions

Comparing version 0.8.26 to 0.9.0-next.1

lib/external_signers/arbitrary.d.ts

18

lib/CosmosSigner.d.ts

@@ -1,2 +0,3 @@

import type { Signature, SessionSigner, Action, Message, Session } from "@canvas-js/interfaces";
import type { Session } from "@canvas-js/interfaces";
import { AbstractSessionData, AbstractSessionSigner, Ed25519DelegateSigner } from "@canvas-js/signatures";
import { CosmosSessionData, ExternalCosmosSigner } from "./types.js";

@@ -8,16 +9,11 @@ export interface CosmosSignerInit {

}
export declare class CosmosSigner implements SessionSigner {
export declare class CosmosSigner extends AbstractSessionSigner<CosmosSessionData> {
#private;
readonly key: string;
readonly sessionDuration: number | null;
private readonly log;
readonly codecs: ("dag-cbor" | "dag-json")[];
constructor({ signer, sessionDuration, bech32Prefix }?: CosmosSignerInit);
readonly match: (address: string) => boolean;
readonly verify: typeof Ed25519DelegateSigner.verify;
verifySession(topic: string, session: Session): Promise<void>;
getSession(topic: string, options?: {
timestamp?: number;
fromCache?: boolean;
}): Promise<Session<CosmosSessionData>>;
sign(message: Message<Action | Session>): Signature;
clear(topic: string): Promise<void>;
protected getAddress(): Promise<string>;
protected newSession(data: AbstractSessionData): Promise<Session<CosmosSessionData>>;
}

@@ -12,17 +12,17 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {

};
var _CosmosSigner_signer, _CosmosSigner_store;
import { logger } from "@libp2p/logger";
import { Secp256k1Signer, didKeyPattern } from "@canvas-js/signed-cid";
import { assert, signalInvalidType, validateSessionData, addressPattern, parseAddress } from "./utils.js";
var _CosmosSigner_signer;
import { AbstractSessionSigner, Ed25519DelegateSigner } from "@canvas-js/signatures";
import { addressPattern, parseAddress } from "./utils.js";
import { createDefaultSigner } from "./external_signers/default.js";
import { createEthereumSigner, verifyEthereum } from "./external_signers/ethereum.js";
import { createAminoSigner, verifyAmino } from "./external_signers/amino.js";
import { createBytesSigner, verifyBytes } from "./external_signers/bytes.js";
import target from "#target";
export class CosmosSigner {
import { createEthereumSigner, validateEthereumSignedSessionData, verifyEthereum } from "./external_signers/ethereum.js";
import { createAminoSigner, validateAminoSignedSessionData, verifyAmino } from "./external_signers/amino.js";
import { createBytesSigner, validateBytesSignedSessionData, verifyBytes } from "./external_signers/bytes.js";
import { createArbitrarySigner, validateArbitrarySignedSessionData, verifyArbitrary, } from "./external_signers/arbitrary.js";
export class CosmosSigner extends AbstractSessionSigner {
constructor({ signer, sessionDuration, bech32Prefix } = {}) {
this.log = logger("canvas:chain-cosmos");
super("chain-cosmos", { createSigner: (init) => new Ed25519DelegateSigner(init), defaultDuration: sessionDuration });
this.codecs = [Ed25519DelegateSigner.cborCodec, Ed25519DelegateSigner.jsonCodec];
_CosmosSigner_signer.set(this, void 0);
_CosmosSigner_store.set(this, target.getSessionStore());
this.match = (address) => addressPattern.test(address);
this.verify = Ed25519DelegateSigner.verify;
const bech32Prefix_ = bech32Prefix == undefined ? "cosmos" : bech32Prefix;

@@ -41,12 +41,11 @@ if (signer == undefined) {

}
else if (signer.type == "arbitrary") {
__classPrivateFieldSet(this, _CosmosSigner_signer, createArbitrarySigner(signer), "f");
}
else {
throw new Error("invalid signer");
}
this.sessionDuration = sessionDuration ?? null;
this.key = `CosmosSigner-${signer ? "signer-" + signer.type : "burner"}`;
}
async verifySession(topic, session) {
const { publicKey, address, authorizationData: data, timestamp, duration } = session;
assert(didKeyPattern.test(publicKey), "invalid signing key");
assert(validateSessionData(data), "invalid session");
const [chainId, walletAddress] = parseAddress(address);

@@ -57,3 +56,3 @@ const message = {

chainId,
uri: publicKey,
publicKey: publicKey,
issuedAt: new Date(timestamp).toISOString(),

@@ -64,38 +63,37 @@ expirationTime: duration === null ? null : new Date(timestamp + duration).toISOString(),

if (data.signatureType == "ethereum") {
if (!validateEthereumSignedSessionData(data)) {
throw new Error("invalid ethereum session data");
}
verifyEthereum(message, data);
}
else if (data.signatureType == "amino") {
if (!validateAminoSignedSessionData(data)) {
throw new Error("invalid amino session data");
}
await verifyAmino(message, data);
}
else if (data.signatureType == "bytes") {
if (!validateBytesSignedSessionData(data)) {
throw new Error("invalid bytes session data");
}
verifyBytes(message, data);
}
else if (data.signatureType == "arbitrary") {
if (!validateArbitrarySignedSessionData(data)) {
throw new Error("invalid arbitrary session data");
}
await verifyArbitrary(message, data);
}
else {
signalInvalidType(data.signatureType);
throw new Error("invalid signature type");
}
}
async getSession(topic, options = {}) {
async getAddress() {
const chainId = await __classPrivateFieldGet(this, _CosmosSigner_signer, "f").getChainId();
const walletAddress = await __classPrivateFieldGet(this, _CosmosSigner_signer, "f").getAddress(chainId);
const address = `cosmos:${chainId}:${walletAddress}`;
this.log("getting session for %s", address);
{
const { signer, session } = (await __classPrivateFieldGet(this, _CosmosSigner_store, "f").get(topic, address)) ?? {};
if (session !== undefined && signer !== undefined) {
const { timestamp, duration } = session;
const t = options.timestamp ?? timestamp;
if (timestamp <= t && t <= timestamp + (duration ?? Infinity)) {
this.log("found session for %s in store: %o", address, session);
return session;
}
else {
this.log("stored session for %s has expired", address);
}
}
}
if (options.fromCache)
return Promise.reject();
this.log("creating new session for %s", address);
const signer = new Secp256k1Signer();
const timestamp = options.timestamp ?? Date.now();
return `cosmos:${chainId}:${walletAddress}`;
}
async newSession(data) {
const { topic, address, timestamp, publicKey, duration } = data;
const [chainId, walletAddress] = parseAddress(address);
const issuedAt = new Date(timestamp);

@@ -106,49 +104,21 @@ const message = {

chainId,
uri: signer.uri,
publicKey: publicKey,
issuedAt: issuedAt.toISOString(),
expirationTime: null,
};
if (this.sessionDuration !== null) {
message.expirationTime = new Date(timestamp + this.sessionDuration).toISOString();
if (duration !== null) {
message.expirationTime = new Date(timestamp + duration).toISOString();
}
const signResult = await __classPrivateFieldGet(this, _CosmosSigner_signer, "f").sign(message, walletAddress, chainId);
const session = {
return {
type: "session",
address: address,
publicKey: signer.uri,
publicKey: publicKey,
authorizationData: signResult,
blockhash: null,
timestamp,
duration: this.sessionDuration,
timestamp: timestamp,
duration: duration,
};
// save the session and private key in the cache and the store
__classPrivateFieldGet(this, _CosmosSigner_store, "f").set(topic, address, session, signer);
this.log("created new session for %s: %o", address, session);
return session;
}
sign(message) {
if (message.payload.type === "action") {
const { address, timestamp } = message.payload;
const { signer, session } = __classPrivateFieldGet(this, _CosmosSigner_store, "f").get(message.topic, address) ?? {};
assert(signer !== undefined && session !== undefined);
assert(address === session.address);
assert(timestamp >= session.timestamp);
assert(timestamp <= session.timestamp + (session.duration ?? Infinity));
return signer.sign(message);
}
else if (message.payload.type === "session") {
const { signer, session } = __classPrivateFieldGet(this, _CosmosSigner_store, "f").get(message.topic, message.payload.address) ?? {};
assert(signer !== undefined && session !== undefined);
// only sign our own current sessions
assert(message.payload === session);
return signer.sign(message);
}
else {
signalInvalidType(message.payload);
}
}
async clear(topic) {
__classPrivateFieldGet(this, _CosmosSigner_store, "f").clear(topic);
}
}
_CosmosSigner_signer = new WeakMap(), _CosmosSigner_store = new WeakMap();
_CosmosSigner_signer = new WeakMap();

@@ -13,13 +13,8 @@ import { AminoSignResponse, StdSignDoc } from "@keplr-wallet/types";

sign: (cosmosMessage: CosmosMessage, address: string, chainId: string) => Promise<{
signature: {
signature: Uint8Array;
pub_key: {
type: "tendermint/PubKeySecp256k1";
value: Uint8Array;
};
};
signature: Uint8Array;
signatureType: "amino";
}>;
};
export declare const verifyAmino: (message: CosmosMessage, sessionData: AminoSignedSessionData) => Promise<void>;
export declare const verifyAmino: (message: CosmosMessage, { signature }: AminoSignedSessionData) => Promise<void>;
export type AminoSignedSessionData = Awaited<ReturnType<ReturnType<typeof createAminoSigner>["sign"]>>;
export declare function validateAminoSignedSessionData(data: any): data is AminoSignedSessionData;
import * as cbor from "@ipld/dag-cbor";
import { base64 } from "multiformats/bases/base64";
import { pubkeyType, rawSecp256k1PubkeyToRawAddress, serializeSignDoc } from "@cosmjs/amino";
import { rawSecp256k1PubkeyToRawAddress, serializeSignDoc } from "@cosmjs/amino";
import { getSessionSignatureData } from "../signatureData.js";

@@ -13,13 +13,7 @@ import { fromBech32, toBech32 } from "@cosmjs/encoding";

const msg = cbor.encode(cosmosMessage);
const signDoc = await getSessionSignatureData(msg, address);
const signDoc = getSessionSignatureData(msg, address);
const signRes = await signer.signAmino(chainId, address, signDoc);
const stdSig = signRes.signature;
return {
signature: {
signature: base64.baseDecode(stdSig.signature),
pub_key: {
type: pubkeyType.secp256k1,
value: base64.baseDecode(stdSig.pub_key.value),
},
},
signature: base64.baseDecode(stdSig.signature),
signatureType: "amino",

@@ -29,20 +23,23 @@ };

});
export const verifyAmino = async (message, sessionData) => {
const { pub_key: { value: pub_key }, signature, } = sessionData.signature;
export const verifyAmino = async (message, { signature }) => {
const walletAddress = message.address;
const { prefix } = fromBech32(walletAddress);
if (walletAddress !== toBech32(prefix, rawSecp256k1PubkeyToRawAddress(pub_key))) {
throw new Error("Session signed with a pubkey that doesn't match the session address");
}
// the payload can either be signed directly, or encapsulated in a SignDoc
const encodedMessage = cbor.encode(message);
const signDocPayload = await getSessionSignatureData(encodedMessage, walletAddress);
const signDocPayload = getSessionSignatureData(encodedMessage, walletAddress);
const signDocDigest = sha256(serializeSignDoc(signDocPayload));
const digest = sha256(encodedMessage);
// compare the signature against the directly signed and signdoc digests
let isValid = false;
isValid || (isValid = secp256k1.verify(signature, signDocDigest, pub_key));
isValid || (isValid = secp256k1.verify(signature, digest, pub_key));
if (!isValid)
throw Error("invalid signature");
// try with both values of the recovery bit
for (const recoveryBit of [0, 1]) {
const signatureWithRecoveryBit = secp256k1.Signature.fromCompact(signature).addRecoveryBit(recoveryBit);
// get the public key from the signature and digest
const pub_key = signatureWithRecoveryBit.recoverPublicKey(signDocDigest).toRawBytes();
// get the address from the public key
const address = toBech32(prefix, rawSecp256k1PubkeyToRawAddress(pub_key));
if (address == walletAddress)
return;
}
throw Error("invalid signature");
};
export function validateAminoSignedSessionData(data) {
return data.signatureType == "amino" && data.signature instanceof Uint8Array;
}

@@ -27,1 +27,2 @@ import { CosmosMessage } from "../types.js";

export type BytesSignedSessionData = Awaited<ReturnType<ReturnType<typeof createBytesSigner>["sign"]>>;
export declare function validateBytesSignedSessionData(data: any): data is BytesSignedSessionData;

@@ -36,1 +36,9 @@ import * as cbor from "@ipld/dag-cbor";

};
export function validateBytesSignedSessionData(data) {
return (data.signatureType == "bytes" &&
data.signature instanceof Uint8Array &&
data.signature.pub_key instanceof Object &&
data.signature.pub_key.value instanceof Uint8Array &&
typeof data.signature.pub_key.type === "string" &&
data.signature.pub_key.type == pubkeyType.secp256k1);
}

@@ -19,1 +19,2 @@ import { CosmosMessage } from "../types.js";

export type EthereumSignedSessionData = Awaited<ReturnType<ReturnType<typeof createEthereumSigner>["sign"]>>;
export declare function validateEthereumSignedSessionData(data: any): data is EthereumSignedSessionData;
import { fromBech32, toBech32 } from "@cosmjs/encoding";
import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
import { verifyMessage } from "ethers";
import { verifyMessage, getBytes, hexlify } from "ethers";
export function encodeReadableEthereumMessage(message) {

@@ -11,3 +10,3 @@ return `

issuedAt: ${message.issuedAt}
uri: ${message.uri}
uri: ${message.publicKey}
`;

@@ -17,4 +16,5 @@ }

getAddress: async (chainId) => {
const address = (await signer.getAddress(chainId)).substring(2);
return toBech32(bech32Prefix, hexToBytes(address));
const address = await signer.getAddress(chainId);
// this assumes that `address` is an ethereum hex address prefixed by 0x
return toBech32(bech32Prefix, getBytes(address));
},

@@ -24,6 +24,7 @@ getChainId: signer.getChainId,

const encodedMessage = encodeReadableEthereumMessage(cosmosMessage);
const ethAddress = `0x${bytesToHex(fromBech32(signerAddress).data)}`;
const hexSignature = await signer.signEthereum(chainId, ethAddress, encodedMessage);
const ethAddress = hexlify(fromBech32(signerAddress).data);
const signature = await signer.signEthereum(chainId, ethAddress, encodedMessage);
// signature is a hex string prefixed by 0x
return {
signature: hexToBytes(hexSignature.substring(2)),
signature: getBytes(signature),
signatureType: "ethereum",

@@ -37,7 +38,10 @@ };

// validate ethereum signature
const recoveredAddress = verifyMessage(encodedReadableMessage, `0x${bytesToHex(sessionData.signature)}`);
const recoveredAddress = verifyMessage(encodedReadableMessage, hexlify(sessionData.signature));
const { prefix } = fromBech32(walletAddress);
if (toBech32(prefix, hexToBytes(recoveredAddress.substring(2))) !== walletAddress) {
if (toBech32(prefix, getBytes(recoveredAddress)) !== walletAddress) {
throw Error("invalid signature");
}
};
export function validateEthereumSignedSessionData(data) {
return data.signatureType == "ethereum" && data.signature instanceof Uint8Array;
}

@@ -1,2 +0,1 @@

import type { StdSignDoc } from "@cosmjs/amino";
export declare const getSessionSignatureData: (sessionPayload: Uint8Array, address: string, chain_id?: string) => Promise<StdSignDoc>;
export declare const getSessionSignatureData: (sessionPayload: Uint8Array, address: string, chain_id?: string) => import("@cosmjs/amino").StdSignDoc;
import { makeSignDoc } from "@cosmjs/amino";
import { toBase64 } from "@cosmjs/encoding";
export const getSessionSignatureData = async (sessionPayload, address, chain_id) => {
export const getSessionSignatureData = (sessionPayload, address, chain_id) => {
const accountNumber = 0;

@@ -5,0 +5,0 @@ const sequence = 0;

import type { EthereumSignedSessionData, EthereumSigner } from "./external_signers/ethereum.js";
import type { BytesSignedSessionData, BytesSigner } from "./external_signers/bytes.js";
import type { AminoSignedSessionData, AminoSigner } from "./external_signers/amino.js";
import { ArbitrarySignedSessionData, ArbitrarySigner } from "./external_signers/arbitrary.js";
export type CosmosMessage = {

@@ -8,7 +9,7 @@ topic: string;

chainId: string;
uri: string;
publicKey: string;
issuedAt: string;
expirationTime: string | null;
};
export type CosmosSessionData = EthereumSignedSessionData | BytesSignedSessionData | AminoSignedSessionData;
export type ExternalCosmosSigner = EthereumSigner | AminoSigner | BytesSigner;
export type CosmosSessionData = EthereumSignedSessionData | BytesSignedSessionData | AminoSignedSessionData | ArbitrarySignedSessionData;
export type ExternalCosmosSigner = EthereumSigner | AminoSigner | BytesSigner | ArbitrarySigner;

@@ -1,6 +0,2 @@

import type { CosmosSessionData } from "./types.js";
export declare function assert(condition: boolean, message?: string): asserts condition;
export declare function signalInvalidType(type: never): never;
export declare const addressPattern: RegExp;
export declare function parseAddress(address: string): [chain: string, walletAddress: string];
export declare function validateSessionData(data: unknown): data is CosmosSessionData;

@@ -1,10 +0,1 @@

export function assert(condition, message) {
if (!condition) {
throw new Error(message ?? "assertion failed");
}
}
export function signalInvalidType(type) {
console.error(type);
throw new TypeError("internal error: invalid type");
}
export const addressPattern = /^cosmos:([0-9a-z\-_]+):([a-zA-Fa-f0-9]+)$/;

@@ -19,29 +10,9 @@ export function parseAddress(address) {

}
export function validateSessionData(data) {
try {
extractSessionData(data);
}
catch (error) {
return false;
}
return true;
}
function extractSessionData(data) {
if (data.signatureType == "amino") {
const signature = data.signature.signature;
const pub_key_value = data.signature.pub_key.value;
const pub_key_type = data.signature.pub_key.type;
if (signature instanceof Uint8Array &&
pub_key_value instanceof Uint8Array &&
typeof pub_key_type === "string" &&
pub_key_type == "tendermint/PubKeySecp256k1") {
const signature = data.signature;
if (signature instanceof Uint8Array) {
return {
signatureType: "amino",
signature: {
signature: signature,
pub_key: {
type: pub_key_type,
value: pub_key_value,
},
},
signature,
};

@@ -79,3 +50,18 @@ }

}
else if (data.signatureType == "arbitrary") {
const signature = data.signature;
if (signature.pub_key instanceof Object && signature.signature instanceof Uint8Array) {
return {
signatureType: "arbitrary",
signature: {
pub_key: {
type: signature.pub_key.type,
value: signature.pub_key.value,
},
signature: signature.signature,
},
};
}
}
throw Error(`invalid session data`);
}
{
"name": "@canvas-js/chain-cosmos",
"version": "0.8.26",
"version": "0.9.0-next.1",
"type": "module",

@@ -11,12 +11,6 @@ "author": "Canvas Technologies, Inc. (https://canvas.xyz)",

],
"imports": {
"#target": {
"node": "./lib/targets/node/index.js",
"browser": "./lib/targets/browser/index.js",
"default": "./lib/targets/default/index.js"
}
},
"dependencies": {
"@canvas-js/interfaces": "0.8.26",
"@canvas-js/signed-cid": "0.8.26",
"@canvas-js/interfaces": "0.9.0-next.1",
"@canvas-js/signatures": "0.9.0-next.1",
"@canvas-js/utils": "0.9.0-next.1",
"@cosmjs/amino": "^0.30.1",

@@ -31,4 +25,5 @@ "@cosmjs/crypto": "^0.30.1",

"@noble/hashes": "^1.3.2",
"ethers": "^6.9.0",
"multiformats": "^13.0.1"
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc