diff --git a/package-lock.json b/package-lock.json index 1d6bff5ab..6f6ebb281 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@noble/secp256k1": "^1.5.2", "@stardazed/streams-polyfill": "^2.4.0", - "@xmtp/proto": "^1.3.1", + "@xmtp/proto": "~3.0.0", "ethers": "^5.5.3", "long": "^5.2.0", "node-localstorage": "^2.2.1" @@ -3134,9 +3134,9 @@ } }, "node_modules/@xmtp/proto": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@xmtp/proto/-/proto-1.3.1.tgz", - "integrity": "sha512-qpZd1/gcjz9I8rB7wAsriKfpu41rpomuIsSVyDg0yGOOPJV+thNSA6UqAs2XNDO68dPSOhFWkROHEdixVnMJPg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@xmtp/proto/-/proto-3.0.0.tgz", + "integrity": "sha512-JJ2h+1SxzocSBnex5BN900HVglRyGC5M7eypl0rFpugVj4Q4//A67ZtB5rSul74MVRrypNbcYXRZRAwI8U9TBg==", "dependencies": { "long": "^5.2.0", "protobufjs": "^7.0.0", @@ -15938,9 +15938,9 @@ "requires": {} }, "@xmtp/proto": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@xmtp/proto/-/proto-1.3.1.tgz", - "integrity": "sha512-qpZd1/gcjz9I8rB7wAsriKfpu41rpomuIsSVyDg0yGOOPJV+thNSA6UqAs2XNDO68dPSOhFWkROHEdixVnMJPg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@xmtp/proto/-/proto-3.0.0.tgz", + "integrity": "sha512-JJ2h+1SxzocSBnex5BN900HVglRyGC5M7eypl0rFpugVj4Q4//A67ZtB5rSul74MVRrypNbcYXRZRAwI8U9TBg==", "requires": { "long": "^5.2.0", "protobufjs": "^7.0.0", diff --git a/package.json b/package.json index db8c2e634..0804bf8b3 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "dependencies": { "@noble/secp256k1": "^1.5.2", "@stardazed/streams-polyfill": "^2.4.0", - "@xmtp/proto": "^1.3.1", + "@xmtp/proto": "~3.0.0", "ethers": "^5.5.3", "long": "^5.2.0", "node-localstorage": "^2.2.1" diff --git a/src/ContactBundle.ts b/src/ContactBundle.ts index 6ad800879..194c84896 100644 --- a/src/ContactBundle.ts +++ b/src/ContactBundle.ts @@ -1,9 +1,9 @@ -import { xmtpEnvelope as proto } from '@xmtp/proto' +import { contact, publicKey } from '@xmtp/proto' import { PublicKeyBundle } from './crypto' import PublicKey from './crypto/PublicKey' // ContactBundle packages all the infromation which a client uses to advertise on the network. -export default class ContactBundle implements proto.ContactBundleV1 { +export default class ContactBundle implements contact.ContactBundleV1 { keyBundle: PublicKeyBundle constructor(publicKeyBundle: PublicKeyBundle) { @@ -14,10 +14,11 @@ export default class ContactBundle implements proto.ContactBundleV1 { } toBytes(): Uint8Array { - return proto.ContactBundle.encode({ + return contact.ContactBundle.encode({ v1: { keyBundle: this.keyBundle, }, + v2: undefined, }).finish() } @@ -42,9 +43,9 @@ export default class ContactBundle implements proto.ContactBundleV1 { ) } - static decodeV1(bytes: Uint8Array): proto.PublicKeyBundle | undefined { + static decodeV1(bytes: Uint8Array): publicKey.PublicKeyBundle | undefined { try { - const b = proto.ContactBundle.decode(bytes) + const b = contact.ContactBundle.decode(bytes) return b.v1?.keyBundle } catch (e) { if ( @@ -53,7 +54,7 @@ export default class ContactBundle implements proto.ContactBundleV1 { ) { // Adds a default fallback for older versions of the proto (Which may also fail) try { - return proto.PublicKeyBundle.decode(bytes) + return publicKey.PublicKeyBundle.decode(bytes) } catch (e) { throw new Error("Couldn't decode contact bundle: " + e) } diff --git a/src/Message.ts b/src/Message.ts index a83660da1..706b1e3ed 100644 --- a/src/Message.ts +++ b/src/Message.ts @@ -13,7 +13,7 @@ import { bytesToHex } from './crypto/utils' import { sha256 } from './crypto/encryption' import { ContentTypeId } from './MessageContent' -const extractV1Message = (msg: proto.Message): proto.V1Message => { +const extractV1Message = (msg: proto.Message): proto.MessageV1 => { if (!msg.v1) { throw new Error('Message is not of type v1') } @@ -23,8 +23,8 @@ const extractV1Message = (msg: proto.Message): proto.V1Message => { // Message is basic unit of communication on the network. // Message header carries the sender and recipient keys used to protect message. // Message timestamp is set by the sender. -export default class Message implements proto.V1Message { - header: proto.MessageHeader // eslint-disable-line camelcase +export default class Message implements proto.MessageV1 { + header: proto.MessageHeaderV1 // eslint-disable-line camelcase headerBytes: Uint8Array // encoded header bytes ciphertext: Ciphertext decrypted?: Uint8Array @@ -46,7 +46,7 @@ export default class Message implements proto.V1Message { id: string, bytes: Uint8Array, obj: proto.Message, - header: proto.MessageHeader + header: proto.MessageHeaderV1 ) { const msg = extractV1Message(obj) this.id = id @@ -65,7 +65,7 @@ export default class Message implements proto.V1Message { static async create( obj: proto.Message, - header: proto.MessageHeader, + header: proto.MessageHeaderV1, bytes: Uint8Array ): Promise { const id = bytesToHex(await sha256(bytes)) @@ -75,7 +75,7 @@ export default class Message implements proto.V1Message { static async fromBytes(bytes: Uint8Array): Promise { const msg = proto.Message.decode(bytes) const innerMessage = extractV1Message(msg) - const header = proto.MessageHeader.decode(innerMessage.headerBytes) + const header = proto.MessageHeaderV1.decode(innerMessage.headerBytes) return Message.create(msg, header, bytes) } @@ -116,14 +116,17 @@ export default class Message implements proto.V1Message { false ) // eslint-disable-next-line camelcase - const header: proto.MessageHeader = { + const header: proto.MessageHeaderV1 = { sender: sender.getPublicKeyBundle(), recipient, timestamp: Long.fromNumber(timestamp.getTime()), } - const headerBytes = proto.MessageHeader.encode(header).finish() + const headerBytes = proto.MessageHeaderV1.encode(header).finish() const ciphertext = await encrypt(message, secret, headerBytes) - const protoMsg = { v1: { headerBytes: headerBytes, ciphertext } } + const protoMsg = { + v1: { headerBytes: headerBytes, ciphertext }, + v2: undefined, + } const bytes = proto.Message.encode(protoMsg).finish() const msg = await Message.create(protoMsg, header, bytes) msg.decrypted = message @@ -139,7 +142,7 @@ export default class Message implements proto.V1Message { ): Promise { const message = proto.Message.decode(bytes) const v1Message = extractV1Message(message) - const header = proto.MessageHeader.decode(v1Message.headerBytes) + const header = proto.MessageHeaderV1.decode(v1Message.headerBytes) if (!header) { throw new Error('missing message header') } diff --git a/src/authn/Authenticator.ts b/src/authn/Authenticator.ts index c8a26bd9a..f073361ba 100644 --- a/src/authn/Authenticator.ts +++ b/src/authn/Authenticator.ts @@ -1,5 +1,5 @@ import { keccak256 } from 'js-sha3' -import { authn, xmtpEnvelope } from '@xmtp/proto' +import { authn, signature, publicKey } from '@xmtp/proto' import AuthData from './AuthData' import { PrivateKey } from '../crypto' import { hexToBytes } from '../crypto/utils' @@ -26,7 +26,7 @@ export default class Authenticator { return new Token( authn.Token.fromPartial({ - identityKey: xmtpEnvelope.PublicKey.fromPartial( + identityKey: publicKey.PublicKey.fromPartial( // The generated types are overly strict and don't like our additional methods // eslint-disable-next-line // @ts-ignore @@ -36,7 +36,7 @@ export default class Authenticator { // The generated types are overly strict and don't like our additional methods // eslint-disable-next-line // @ts-ignore - authDataSignature: xmtpEnvelope.Signature.fromPartial(authSig), + authDataSignature: signature.Signature.fromPartial(authSig), }) ) } diff --git a/src/authn/Token.ts b/src/authn/Token.ts index 7bf70a349..472101eb1 100644 --- a/src/authn/Token.ts +++ b/src/authn/Token.ts @@ -1,10 +1,10 @@ -import { authn, xmtpEnvelope } from '@xmtp/proto' +import { authn, signature, publicKey } from '@xmtp/proto' import AuthData from './AuthData' export default class Token implements authn.Token { - identityKey: xmtpEnvelope.PublicKey + identityKey: publicKey.PublicKey authDataBytes: Uint8Array - authDataSignature: xmtpEnvelope.Signature + authDataSignature: signature.Signature private _authData?: AuthData constructor({ identityKey, authDataBytes, authDataSignature }: authn.Token) { diff --git a/src/crypto/Ciphertext.ts b/src/crypto/Ciphertext.ts index a69ed845c..941ebbc14 100644 --- a/src/crypto/Ciphertext.ts +++ b/src/crypto/Ciphertext.ts @@ -1,4 +1,4 @@ -import { xmtpEnvelope as proto } from '@xmtp/proto' +import { ciphertext } from '@xmtp/proto' export const AESKeySize = 32 // bytes export const KDFSaltSize = 32 // bytes @@ -8,10 +8,10 @@ export const AESGCMTagLength = 16 // property tagLength // Ciphertext packages the encrypted ciphertext with the salt and nonce used to produce it. // salt and nonce are not secret, and should be transmitted/stored along with the encrypted ciphertext. -export default class Ciphertext implements proto.Ciphertext { - aes256GcmHkdfSha256: proto.Ciphertext_Aes256gcmHkdfsha256 | undefined // eslint-disable-line camelcase +export default class Ciphertext implements ciphertext.Ciphertext { + aes256GcmHkdfSha256: ciphertext.Ciphertext_Aes256gcmHkdfsha256 | undefined // eslint-disable-line camelcase - constructor(obj: proto.Ciphertext) { + constructor(obj: ciphertext.Ciphertext) { if (!obj.aes256GcmHkdfSha256) { throw new Error('invalid ciphertext') } @@ -34,10 +34,10 @@ export default class Ciphertext implements proto.Ciphertext { } toBytes(): Uint8Array { - return proto.Ciphertext.encode(this).finish() + return ciphertext.Ciphertext.encode(this).finish() } static fromBytes(bytes: Uint8Array): Ciphertext { - return new Ciphertext(proto.Ciphertext.decode(bytes)) + return new Ciphertext(ciphertext.Ciphertext.decode(bytes)) } } diff --git a/src/crypto/PrivateKey.ts b/src/crypto/PrivateKey.ts index be0f3b1b0..58cfd61f8 100644 --- a/src/crypto/PrivateKey.ts +++ b/src/crypto/PrivateKey.ts @@ -1,4 +1,4 @@ -import { privateKey as proto } from '@xmtp/proto' +import { privateKey } from '@xmtp/proto' import * as secp from '@noble/secp256k1' import Long from 'long' import Signature from './Signature' @@ -7,12 +7,12 @@ import Ciphertext from './Ciphertext' import { decrypt, encrypt, sha256 } from './encryption' // PrivateKey represents a secp256k1 private key. -export default class PrivateKey implements proto.PrivateKey { +export default class PrivateKey implements privateKey.PrivateKey { timestamp: Long - secp256k1: proto.PrivateKey_Secp256k1 | undefined // eslint-disable-line camelcase + secp256k1: privateKey.PrivateKey_Secp256k1 | undefined // eslint-disable-line camelcase publicKey: PublicKey // caches corresponding PublicKey - constructor(obj: proto.PrivateKey) { + constructor(obj: privateKey.PrivateKey) { if (!obj.secp256k1) { throw new Error('invalid private key') } @@ -127,10 +127,10 @@ export default class PrivateKey implements proto.PrivateKey { } toBytes(): Uint8Array { - return proto.PrivateKey.encode(this).finish() + return privateKey.PrivateKey.encode(this).finish() } static fromBytes(bytes: Uint8Array): PrivateKey { - return new PrivateKey(proto.PrivateKey.decode(bytes)) + return new PrivateKey(privateKey.PrivateKey.decode(bytes)) } } diff --git a/src/crypto/PublicKey.ts b/src/crypto/PublicKey.ts index 9cb3d3f07..6dea5cd2e 100644 --- a/src/crypto/PublicKey.ts +++ b/src/crypto/PublicKey.ts @@ -1,4 +1,4 @@ -import { xmtpEnvelope as proto } from '@xmtp/proto' +import { publicKey } from '@xmtp/proto' import * as secp from '@noble/secp256k1' import Long from 'long' import Signature from './Signature' @@ -9,12 +9,12 @@ import { sha256 } from './encryption' // PublicKey represents uncompressed secp256k1 public key, // that can optionally be signed with another trusted key pair. // PublicKeys can be generated through PrivateKey.generate() -export default class PublicKey implements proto.PublicKey { +export default class PublicKey implements publicKey.PublicKey { timestamp: Long - secp256k1Uncompressed: proto.PublicKey_Secp256k1Uncompressed // eslint-disable-line camelcase + secp256k1Uncompressed: publicKey.PublicKey_Secp256k1Uncompressed // eslint-disable-line camelcase signature?: Signature - constructor(obj: proto.PublicKey) { + constructor(obj: publicKey.PublicKey) { if (!obj?.secp256k1Uncompressed?.bytes) { throw new Error('invalid public key') } @@ -58,7 +58,7 @@ export default class PublicKey implements proto.PublicKey { } bytesToSign(): Uint8Array { - return proto.PublicKey.encode({ + return publicKey.PublicKey.encode({ timestamp: this.timestamp, secp256k1Uncompressed: this.secp256k1Uncompressed, }).finish() @@ -154,10 +154,10 @@ export default class PublicKey implements proto.PublicKey { } toBytes(): Uint8Array { - return proto.PublicKey.encode(this).finish() + return publicKey.PublicKey.encode(this).finish() } static fromBytes(bytes: Uint8Array): PublicKey { - return new PublicKey(proto.PublicKey.decode(bytes)) + return new PublicKey(publicKey.PublicKey.decode(bytes)) } } diff --git a/src/crypto/PublicKeyBundle.ts b/src/crypto/PublicKeyBundle.ts index 65412e118..0b0ad7167 100644 --- a/src/crypto/PublicKeyBundle.ts +++ b/src/crypto/PublicKeyBundle.ts @@ -1,10 +1,10 @@ -import { xmtpEnvelope as proto } from '@xmtp/proto' +import { publicKey } from '@xmtp/proto' import PublicKey from './PublicKey' // PublicKeyBundle packages all the keys that a participant should advertise. // The PreKey must be signed by the IdentityKey. // The IdentityKey can be signed by the wallet to authenticate it. -export default class PublicKeyBundle implements proto.PublicKeyBundle { +export default class PublicKeyBundle implements publicKey.PublicKeyBundle { identityKey: PublicKey preKey: PublicKey @@ -24,11 +24,11 @@ export default class PublicKeyBundle implements proto.PublicKeyBundle { } toBytes(): Uint8Array { - return proto.PublicKeyBundle.encode(this).finish() + return publicKey.PublicKeyBundle.encode(this).finish() } static fromBytes(bytes: Uint8Array): PublicKeyBundle { - const decoded = proto.PublicKeyBundle.decode(bytes) + const decoded = publicKey.PublicKeyBundle.decode(bytes) if (!decoded.identityKey) { throw new Error('missing identity key') } diff --git a/src/crypto/Signature.ts b/src/crypto/Signature.ts index 565ff2fe7..dfe760850 100644 --- a/src/crypto/Signature.ts +++ b/src/crypto/Signature.ts @@ -1,13 +1,14 @@ -import { xmtpEnvelope as proto } from '@xmtp/proto' +import { signature } from '@xmtp/proto' import Long from 'long' import * as secp from '@noble/secp256k1' import PublicKey from './PublicKey' // Signature represents an ECDSA signature with recovery bit. -export default class Signature implements proto.Signature { - ecdsaCompact: proto.Signature_ECDSACompact | undefined // eslint-disable-line camelcase +export default class Signature implements signature.Signature { + ecdsaCompact: signature.Signature_ECDSACompact | undefined // eslint-disable-line camelcase + walletEcdsaCompact: signature.Signature_WalletECDSACompact | undefined // eslint-disable-line camelcase - constructor(obj: proto.Signature) { + constructor(obj: Partial) { if (!obj.ecdsaCompact) { throw new Error('invalid signature') } @@ -43,10 +44,10 @@ export default class Signature implements proto.Signature { } toBytes(): Uint8Array { - return proto.Signature.encode(this).finish() + return signature.Signature.encode(this).finish() } static fromBytes(bytes: Uint8Array): Signature { - return new Signature(proto.Signature.decode(bytes)) + return new Signature(signature.Signature.decode(bytes)) } } diff --git a/test/ContentTypeTestKey.ts b/test/ContentTypeTestKey.ts index 85d3b8505..1a66ac1a9 100644 --- a/test/ContentTypeTestKey.ts +++ b/test/ContentTypeTestKey.ts @@ -1,4 +1,4 @@ -import { xmtpEnvelope as proto } from '@xmtp/proto' +import { publicKey } from '@xmtp/proto' import { ContentTypeId, ContentCodec, PublicKey, EncodedContent } from '../src' export const ContentTypeTestKey = new ContentTypeId({ @@ -17,11 +17,11 @@ export class TestKeyCodec implements ContentCodec { return { type: ContentTypeTestKey, parameters: {}, - content: proto.PublicKey.encode(key).finish(), + content: publicKey.PublicKey.encode(key).finish(), } } decode(content: EncodedContent): PublicKey { - return new PublicKey(proto.PublicKey.decode(content.content)) + return new PublicKey(publicKey.PublicKey.decode(content.content)) } } diff --git a/test/helpers.ts b/test/helpers.ts index a582cec91..9a143395c 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -11,8 +11,8 @@ import { import Stream from '../src/Stream' import { promiseWithTimeout } from '../src/utils' import assert from 'assert' -import { xmtpEnvelope } from '@xmtp/proto' -type PublicKeyBundle = xmtpEnvelope.PublicKeyBundle +import { publicKey } from '@xmtp/proto' +type PublicKeyBundle = publicKey.PublicKeyBundle export const sleep = (ms: number): Promise => new Promise((resolve) => setTimeout(resolve, ms))