fix: ts and lint errors

This commit is contained in:
Hugo Dias 2021-01-26 21:39:37 +00:00
parent 2df5f9546e
commit ead151471e
No known key found for this signature in database
GPG Key ID: 9F61AFCAB8C717A0
22 changed files with 168 additions and 161 deletions

12
src/@types/basic.d.ts vendored
View File

@ -1,8 +1,8 @@
import {Buffer} from 'buffer'; import { Buffer } from 'buffer'
export type bytes = Buffer; export type bytes = Buffer
export type bytes32 = Buffer; export type bytes32 = Buffer
export type bytes16 = Buffer; export type bytes16 = Buffer
export type uint32 = number; export type uint32 = number
export type uint64 = number; export type uint64 = number

View File

@ -1,11 +1,11 @@
import {bytes} from "./basic"; import { bytes } from './basic'
import {NoiseSession} from "./handshake"; import { NoiseSession } from './handshake'
import PeerId from "peer-id"; import PeerId from 'peer-id'
export interface IHandshake { export interface IHandshake {
session: NoiseSession; session: NoiseSession
remotePeer: PeerId; remotePeer: PeerId
remoteEarlyData: Buffer; remoteEarlyData: Buffer
encrypt(plaintext: bytes, session: NoiseSession): bytes; encrypt: (plaintext: bytes, session: NoiseSession) => bytes
decrypt(ciphertext: bytes, session: NoiseSession): {plaintext: bytes; valid: boolean}; decrypt: (ciphertext: bytes, session: NoiseSession) => {plaintext: bytes, valid: boolean}
} }

View File

@ -1,45 +1,45 @@
import {bytes, bytes32, uint32, uint64} from "./basic"; import { bytes, bytes32, uint32, uint64 } from './basic'
import {KeyPair} from "./libp2p"; import { KeyPair } from './libp2p'
export type Hkdf = [bytes, bytes, bytes]; export type Hkdf = [bytes, bytes, bytes]
export type MessageBuffer = { export interface MessageBuffer {
ne: bytes32; ne: bytes32
ns: bytes; ns: bytes
ciphertext: bytes; ciphertext: bytes
} }
export type CipherState = { export interface CipherState {
k: bytes32; k: bytes32
n: uint32; n: uint32
} }
export type SymmetricState = { export interface SymmetricState {
cs: CipherState; cs: CipherState
ck: bytes32; // chaining key ck: bytes32 // chaining key
h: bytes32; // handshake hash h: bytes32 // handshake hash
} }
export type HandshakeState = { export interface HandshakeState {
ss: SymmetricState; ss: SymmetricState
s: KeyPair; s: KeyPair
e?: KeyPair; e?: KeyPair
rs: bytes32; rs: bytes32
re: bytes32; re: bytes32
psk: bytes32; psk: bytes32
} }
export type NoiseSession = { export interface NoiseSession {
hs: HandshakeState; hs: HandshakeState
h?: bytes32; h?: bytes32
cs1?: CipherState; cs1?: CipherState
cs2?: CipherState; cs2?: CipherState
mc: uint64; mc: uint64
i: boolean; i: boolean
} }
export interface INoisePayload { export interface INoisePayload {
identityKey: bytes; identityKey: bytes
identitySig: bytes; identitySig: bytes
data: bytes; data: bytes
} }

View File

@ -3,33 +3,33 @@ declare module 'it-length-prefixed' {
import { Buffer } from 'buffer' import { Buffer } from 'buffer'
interface LengthDecoderFunction { interface LengthDecoderFunction {
(data: Buffer | BufferList): number; (data: Buffer | BufferList): number
bytes: number; bytes: number
} }
interface LengthEncoderFunction { interface LengthEncoderFunction {
(value: number, target: Buffer, offset: number): number|Buffer; (value: number, target: Buffer, offset: number): number|Buffer
bytes: number; bytes: number
} }
interface Encoder { interface Encoder {
(options?: Partial<{lengthEncoder: LengthEncoderFunction}>): AsyncGenerator<BufferList, Buffer>; (options?: Partial<{lengthEncoder: LengthEncoderFunction}>): AsyncGenerator<BufferList, Buffer>
single: (chunk: Buffer, options?: Partial<{lengthEncoder: LengthEncoderFunction}>) => BufferList; single: (chunk: Buffer, options?: Partial<{lengthEncoder: LengthEncoderFunction}>) => BufferList
MIN_POOL_SIZE: number; MIN_POOL_SIZE: number
DEFAULT_POOL_SIZE: number; DEFAULT_POOL_SIZE: number
} }
interface DecoderOptions { interface DecoderOptions {
lengthDecoder: LengthDecoderFunction; lengthDecoder: LengthDecoderFunction
maxLengthLength: number; maxLengthLength: number
maxDataLength: number; maxDataLength: number
} }
interface Decoder { interface Decoder {
(options?: Partial<DecoderOptions>): AsyncGenerator<BufferList, BufferList>; (options?: Partial<DecoderOptions>): AsyncGenerator<BufferList, BufferList>
fromReader: (reader: any, options?: Partial<DecoderOptions>) => BufferList; fromReader: (reader: any, options?: Partial<DecoderOptions>) => BufferList
MAX_LENGTH_LENGTH: number; MAX_LENGTH_LENGTH: number
MAX_DATA_LENGTH: number; MAX_DATA_LENGTH: number
} }
export const encode: Encoder export const encode: Encoder

View File

@ -1,8 +1,8 @@
declare module 'it-pair' { declare module 'it-pair' {
export type Duplex = [Stream, Stream]; export type Duplex = [Stream, Stream]
type Stream = { interface Stream {
sink(source: Iterable<any>): void; sink: (source: Iterable<any>) => void
source: Record<string, any>; source: Record<string, any>
} }
} }

View File

@ -1,20 +1,19 @@
import { bytes, bytes32 } from "./basic"; import { bytes, bytes32 } from './basic'
import PeerId from "peer-id"; import PeerId from 'peer-id'
export type KeyPair = { export interface KeyPair {
publicKey: bytes32; publicKey: bytes32
privateKey: bytes32; privateKey: bytes32
} }
export interface INoiseConnection { export interface INoiseConnection {
remoteEarlyData?(): bytes; remoteEarlyData?: () => bytes
secureOutbound(localPeer: PeerId, insecure: any, remotePeer: PeerId): Promise<SecureOutbound>; secureOutbound: (localPeer: PeerId, insecure: any, remotePeer: PeerId) => Promise<SecureOutbound>
secureInbound(localPeer: PeerId, insecure: any, remotePeer: PeerId): Promise<SecureOutbound>; secureInbound: (localPeer: PeerId, insecure: any, remotePeer: PeerId) => Promise<SecureOutbound>
} }
export type SecureOutbound = { export interface SecureOutbound {
conn: any; conn: any
remoteEarlyData: Buffer; remoteEarlyData: Buffer
remotePeer: PeerId; remotePeer: PeerId
} }

View File

@ -3,7 +3,7 @@ import { IHandshake } from './@types/handshake-interface'
import { NOISE_MSG_MAX_LENGTH_BYTES, NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG } from './constants' import { NOISE_MSG_MAX_LENGTH_BYTES, NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG } from './constants'
interface IReturnEncryptionWrapper { interface IReturnEncryptionWrapper {
(source: Iterable<Uint8Array>): AsyncIterableIterator<Uint8Array>; (source: Iterable<Uint8Array>): AsyncIterableIterator<Uint8Array>
} }
// Returns generator that encrypts payload from the user // Returns generator that encrypts payload from the user

View File

@ -1,7 +1,7 @@
import BufferList from 'bl' import BufferList from 'bl'
export class FailedIKError extends Error { export class FailedIKError extends Error {
public initialMsg: string|BufferList|Buffer; public initialMsg: string|BufferList|Buffer
constructor (initialMsg: string|BufferList|Buffer, message?: string) { constructor (initialMsg: string|BufferList|Buffer, message?: string) {
super(message) super(message)

View File

@ -19,16 +19,16 @@ import {
import PeerId from 'peer-id' import PeerId from 'peer-id'
export class IKHandshake implements IHandshake { export class IKHandshake implements IHandshake {
public isInitiator: boolean; public isInitiator: boolean
public session: NoiseSession; public session: NoiseSession
public remotePeer!: PeerId; public remotePeer!: PeerId
public remoteEarlyData: Buffer; public remoteEarlyData: Buffer
private payload: bytes; private readonly payload: bytes
private prologue: bytes32; private readonly prologue: bytes32
private staticKeypair: KeyPair; private readonly staticKeypair: KeyPair
private connection: WrappedConnection; private readonly connection: WrappedConnection
private ik: IK; private readonly ik: IK
constructor ( constructor (
isInitiator: boolean, isInitiator: boolean,
@ -48,7 +48,7 @@ export class IKHandshake implements IHandshake {
if (remotePeer) { if (remotePeer) {
this.remotePeer = remotePeer this.remotePeer = remotePeer
} }
this.ik = handshake || new IK() this.ik = handshake ?? new IK()
this.session = this.ik.initSession(this.isInitiator, this.prologue, this.staticKeypair, remoteStaticKey) this.session = this.ik.initSession(this.isInitiator, this.prologue, this.staticKeypair, remoteStaticKey)
this.remoteEarlyData = Buffer.alloc(0) this.remoteEarlyData = Buffer.alloc(0)
} }
@ -79,9 +79,10 @@ export class IKHandshake implements IHandshake {
logger('IK Stage 0 - Responder successfully verified payload!') logger('IK Stage 0 - Responder successfully verified payload!')
logRemoteEphemeralKey(this.session.hs.re) logRemoteEphemeralKey(this.session.hs.re)
} catch (e) { } catch (e) {
const err = e as Error
logger('Responder breaking up with IK handshake in stage 0.') logger('Responder breaking up with IK handshake in stage 0.')
throw new FailedIKError(receivedMsg, `Error occurred while verifying initiator's signed payload: ${e.message}`) throw new FailedIKError(receivedMsg, `Error occurred while verifying initiator's signed payload: ${err.message}`)
} }
} }
} }
@ -104,8 +105,9 @@ export class IKHandshake implements IHandshake {
logger('IK Stage 1 - Initiator successfully verified payload!') logger('IK Stage 1 - Initiator successfully verified payload!')
logRemoteEphemeralKey(this.session.hs.re) logRemoteEphemeralKey(this.session.hs.re)
} catch (e) { } catch (e) {
const err = e as Error
logger('Initiator breaking up with IK handshake in stage 1.') logger('Initiator breaking up with IK handshake in stage 1.')
throw new FailedIKError(receivedMsg, `Error occurred while verifying responder's signed payload: ${e.message}`) throw new FailedIKError(receivedMsg, `Error occurred while verifying responder's signed payload: ${err.message}`)
} }
} else { } else {
logger('IK Stage 1 - Responder sending message...') logger('IK Stage 1 - Responder sending message...')
@ -117,7 +119,7 @@ export class IKHandshake implements IHandshake {
logCipherState(this.session) logCipherState(this.session)
} }
public decrypt (ciphertext: bytes, session: NoiseSession): {plaintext: bytes; valid: boolean} { public decrypt (ciphertext: bytes, session: NoiseSession): {plaintext: bytes, valid: boolean} {
const cs = this.getCS(session, false) const cs = this.getCS(session, false)
return this.ik.decryptWithAd(cs, Buffer.alloc(0), ciphertext) return this.ik.decryptWithAd(cs, Buffer.alloc(0), ciphertext)
} }

View File

@ -10,8 +10,8 @@ import { decode0, decode1 } from './encoder'
import PeerId from 'peer-id' import PeerId from 'peer-id'
export class XXFallbackHandshake extends XXHandshake { export class XXFallbackHandshake extends XXHandshake {
private ephemeralKeys?: KeyPair; private readonly ephemeralKeys?: KeyPair
private initialMsg: bytes; private readonly initialMsg: bytes
constructor ( constructor (
isInitiator: boolean, isInitiator: boolean,
@ -73,7 +73,8 @@ export class XXFallbackHandshake extends XXHandshake {
await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer) await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer)
this.setRemoteEarlyData(decodedPayload.data) this.setRemoteEarlyData(decodedPayload.data)
} catch (e) { } catch (e) {
throw new Error(`Error occurred while verifying signed payload from responder: ${e.message}`) const err = e as Error
throw new Error(`Error occurred while verifying signed payload from responder: ${err.message}`)
} }
logger('All good with the signature!') logger('All good with the signature!')
} else { } else {

View File

@ -23,17 +23,17 @@ import { WrappedConnection } from './noise'
import PeerId from 'peer-id' import PeerId from 'peer-id'
export class XXHandshake implements IHandshake { export class XXHandshake implements IHandshake {
public isInitiator: boolean; public isInitiator: boolean
public session: NoiseSession; public session: NoiseSession
public remotePeer!: PeerId; public remotePeer!: PeerId
public remoteEarlyData: Buffer; public remoteEarlyData: Buffer
protected payload: bytes; protected payload: bytes
protected connection: WrappedConnection; protected connection: WrappedConnection
protected xx: XX; protected xx: XX
protected staticKeypair: KeyPair; protected staticKeypair: KeyPair
private prologue: bytes32; private readonly prologue: bytes32
constructor ( constructor (
isInitiator: boolean, isInitiator: boolean,
@ -52,7 +52,7 @@ export class XXHandshake implements IHandshake {
if (remotePeer) { if (remotePeer) {
this.remotePeer = remotePeer this.remotePeer = remotePeer
} }
this.xx = handshake || new XX() this.xx = handshake ?? new XX()
this.session = this.xx.initSession(this.isInitiator, this.prologue, this.staticKeypair) this.session = this.xx.initSession(this.isInitiator, this.prologue, this.staticKeypair)
this.remoteEarlyData = Buffer.alloc(0) this.remoteEarlyData = Buffer.alloc(0)
} }
@ -98,7 +98,8 @@ export class XXHandshake implements IHandshake {
this.remotePeer = await verifySignedPayload(receivedMessageBuffer.ns, decodedPayload, this.remotePeer) this.remotePeer = await verifySignedPayload(receivedMessageBuffer.ns, decodedPayload, this.remotePeer)
this.setRemoteEarlyData(decodedPayload.data) this.setRemoteEarlyData(decodedPayload.data)
} catch (e) { } catch (e) {
throw new Error(`Error occurred while verifying signed payload: ${e.message}`) const err = e as Error
throw new Error(`Error occurred while verifying signed payload: ${err.message}`)
} }
logger('All good with the signature!') logger('All good with the signature!')
} else { } else {
@ -132,7 +133,8 @@ export class XXHandshake implements IHandshake {
await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer) await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer)
this.setRemoteEarlyData(decodedPayload.data) this.setRemoteEarlyData(decodedPayload.data)
} catch (e) { } catch (e) {
throw new Error(`Error occurred while verifying signed payload: ${e.message}`) const err = e as Error
throw new Error(`Error occurred while verifying signed payload: ${err.message}`)
} }
} }
logCipherState(this.session) logCipherState(this.session)
@ -144,7 +146,7 @@ export class XXHandshake implements IHandshake {
return this.xx.encryptWithAd(cs, Buffer.alloc(0), plaintext) return this.xx.encryptWithAd(cs, Buffer.alloc(0), plaintext)
} }
public decrypt (ciphertext: bytes, session: NoiseSession): {plaintext: bytes; valid: boolean} { public decrypt (ciphertext: bytes, session: NoiseSession): {plaintext: bytes, valid: boolean} {
const cs = this.getCS(session, false) const cs = this.getCS(session, false)
return this.xx.decryptWithAd(cs, Buffer.alloc(0), ciphertext) return this.xx.decryptWithAd(cs, Buffer.alloc(0), ciphertext)
} }

View File

@ -18,7 +18,7 @@ export abstract class AbstractHandshake {
return e return e
} }
public decryptWithAd (cs: CipherState, ad: bytes, ciphertext: bytes): {plaintext: bytes; valid: boolean} { public decryptWithAd (cs: CipherState, ad: bytes, ciphertext: bytes): {plaintext: bytes, valid: boolean} {
const { plaintext, valid } = this.decrypt(cs.k, cs.n, ad, ciphertext) const { plaintext, valid } = this.decrypt(cs.k, cs.n, ad, ciphertext)
this.setNonce(cs, this.incrementNonce(cs.n)) this.setNonce(cs, this.incrementNonce(cs.n))
@ -78,7 +78,7 @@ export abstract class AbstractHandshake {
return ciphertext return ciphertext
} }
protected decrypt (k: bytes32, n: uint32, ad: bytes, ciphertext: bytes): {plaintext: bytes; valid: boolean} { protected decrypt (k: bytes32, n: uint32, ad: bytes, ciphertext: bytes): {plaintext: bytes, valid: boolean} {
const nonce = this.nonceToBytes(n) const nonce = this.nonceToBytes(n)
const ctx = new AEAD() const ctx = new AEAD()
ciphertext = Buffer.from(ciphertext) ciphertext = Buffer.from(ciphertext)
@ -91,7 +91,7 @@ export abstract class AbstractHandshake {
return { plaintext: ciphertext, valid: ctx.verify(tag) } return { plaintext: ciphertext, valid: ctx.verify(tag) }
} }
protected decryptAndHash (ss: SymmetricState, ciphertext: bytes): {plaintext: bytes; valid: boolean} { protected decryptAndHash (ss: SymmetricState, ciphertext: bytes): {plaintext: bytes, valid: boolean} {
let plaintext: bytes; let valid = true let plaintext: bytes; let valid = true
if (this.hasKey(ss.cs)) { if (this.hasKey(ss.cs)) {
({ plaintext, valid } = this.decryptWithAd(ss.cs, ss.h, ciphertext)) ({ plaintext, valid } = this.decryptWithAd(ss.cs, ss.h, ciphertext))
@ -125,7 +125,7 @@ export abstract class AbstractHandshake {
protected mixKey (ss: SymmetricState, ikm: bytes32): void { protected mixKey (ss: SymmetricState, ikm: bytes32): void {
const [ck, tempK] = getHkdf(ss.ck, ikm) const [ck, tempK] = getHkdf(ss.ck, ikm)
ss.cs = this.initializeKey(tempK) as CipherState ss.cs = this.initializeKey(tempK)
ss.ck = ck ss.ck = ck
} }
@ -173,7 +173,7 @@ export abstract class AbstractHandshake {
return { ne, ns, ciphertext } return { ne, ns, ciphertext }
} }
protected readMessageRegular (cs: CipherState, message: MessageBuffer): {plaintext: bytes; valid: boolean} { protected readMessageRegular (cs: CipherState, message: MessageBuffer): {plaintext: bytes, valid: boolean} {
return this.decryptWithAd(cs, Buffer.alloc(0), message.ciphertext) return this.decryptWithAd(cs, Buffer.alloc(0), message.ciphertext)
} }
} }

View File

@ -55,7 +55,7 @@ export class IK extends AbstractHandshake {
return messageBuffer return messageBuffer
} }
public recvMessage (session: NoiseSession, message: MessageBuffer): {plaintext: bytes; valid: boolean} { public recvMessage (session: NoiseSession, message: MessageBuffer): {plaintext: bytes, valid: boolean} {
let plaintext = Buffer.alloc(0); let valid = false let plaintext = Buffer.alloc(0); let valid = false
if (session.mc === 0) { if (session.mc === 0) {
({ plaintext, valid } = this.readMessageA(session.hs, message)) ({ plaintext, valid } = this.readMessageA(session.hs, message))
@ -101,7 +101,7 @@ export class IK extends AbstractHandshake {
return { messageBuffer, cs1, cs2, h: hs.ss.h } return { messageBuffer, cs1, cs2, h: hs.ss.h }
} }
private readMessageA (hs: HandshakeState, message: MessageBuffer): {plaintext: bytes; valid: boolean} { private readMessageA (hs: HandshakeState, message: MessageBuffer): {plaintext: bytes, valid: boolean} {
if (isValidPublicKey(message.ne)) { if (isValidPublicKey(message.ne)) {
hs.re = message.ne hs.re = message.ne
} }
@ -117,7 +117,7 @@ export class IK extends AbstractHandshake {
return { plaintext, valid: (valid1 && valid2) } return { plaintext, valid: (valid1 && valid2) }
} }
private readMessageB (hs: HandshakeState, message: MessageBuffer): {h: bytes; plaintext: bytes; valid: boolean; cs1: CipherState; cs2: CipherState} { private readMessageB (hs: HandshakeState, message: MessageBuffer): {h: bytes, plaintext: bytes, valid: boolean, cs1: CipherState, cs2: CipherState} {
if (isValidPublicKey(message.ne)) { if (isValidPublicKey(message.ne)) {
hs.re = message.ne hs.re = message.ne
} }

View File

@ -27,7 +27,7 @@ export class XX extends AbstractHandshake {
private writeMessageA (hs: HandshakeState, payload: bytes, e?: KeyPair): MessageBuffer { private writeMessageA (hs: HandshakeState, payload: bytes, e?: KeyPair): MessageBuffer {
const ns = Buffer.alloc(0) const ns = Buffer.alloc(0)
if (e) { if (e !== undefined) {
hs.e = e hs.e = e
} else { } else {
hs.e = generateKeypair() hs.e = generateKeypair()
@ -68,7 +68,7 @@ export class XX extends AbstractHandshake {
return { h: hs.ss.h, messageBuffer, cs1, cs2 } return { h: hs.ss.h, messageBuffer, cs1, cs2 }
} }
private readMessageA (hs: HandshakeState, message: MessageBuffer): {plaintext: bytes; valid: boolean} { private readMessageA (hs: HandshakeState, message: MessageBuffer): {plaintext: bytes, valid: boolean} {
if (isValidPublicKey(message.ne)) { if (isValidPublicKey(message.ne)) {
hs.re = message.ne hs.re = message.ne
} }
@ -77,7 +77,7 @@ export class XX extends AbstractHandshake {
return this.decryptAndHash(hs.ss, message.ciphertext) return this.decryptAndHash(hs.ss, message.ciphertext)
} }
private readMessageB (hs: HandshakeState, message: MessageBuffer): {plaintext: bytes; valid: boolean} { private readMessageB (hs: HandshakeState, message: MessageBuffer): {plaintext: bytes, valid: boolean} {
if (isValidPublicKey(message.ne)) { if (isValidPublicKey(message.ne)) {
hs.re = message.ne hs.re = message.ne
} }
@ -96,7 +96,7 @@ export class XX extends AbstractHandshake {
return { plaintext, valid: (valid1 && valid2) } return { plaintext, valid: (valid1 && valid2) }
} }
private readMessageC (hs: HandshakeState, message: MessageBuffer): {h: bytes; plaintext: bytes; valid: boolean; cs1: CipherState; cs2: CipherState} { private readMessageC (hs: HandshakeState, message: MessageBuffer): {h: bytes, plaintext: bytes, valid: boolean, cs1: CipherState, cs2: CipherState} {
const { plaintext: ns, valid: valid1 } = this.decryptAndHash(hs.ss, message.ns) const { plaintext: ns, valid: valid1 } = this.decryptAndHash(hs.ss, message.ns)
if (valid1 && ns.length === 32 && isValidPublicKey(ns)) { if (valid1 && ns.length === 32 && isValidPublicKey(ns)) {
hs.rs = ns hs.rs = ns
@ -164,7 +164,7 @@ export class XX extends AbstractHandshake {
return messageBuffer return messageBuffer
} }
public recvMessage (session: NoiseSession, message: MessageBuffer): {plaintext: bytes; valid: boolean} { public recvMessage (session: NoiseSession, message: MessageBuffer): {plaintext: bytes, valid: boolean} {
let plaintext: bytes = Buffer.alloc(0) let plaintext: bytes = Buffer.alloc(0)
let valid = false let valid = false
if (session.mc === 0) { if (session.mc === 0) {

View File

@ -5,7 +5,7 @@ import PeerId from 'peer-id'
* Storage for static keys of previously connected peers. * Storage for static keys of previously connected peers.
*/ */
class Keycache { class Keycache {
private storage = new Map<Uint8Array, bytes32>(); private readonly storage = new Map<Uint8Array, bytes32>()
public store (peerId: PeerId, key: bytes32): void { public store (peerId: PeerId, key: bytes32): void {
this.storage.set(peerId.id, key) this.storage.set(peerId.id, key)
@ -15,7 +15,7 @@ class Keycache {
if (!peerId) { if (!peerId) {
return null return null
} }
return this.storage.get(peerId.id) || null return this.storage.get(peerId.id) ?? null
} }
public resetStorage (): void { public resetStorage (): void {

View File

@ -21,22 +21,22 @@ import { logger } from './logger'
import PeerId from 'peer-id' import PeerId from 'peer-id'
import { NOISE_MSG_MAX_LENGTH_BYTES } from './constants' import { NOISE_MSG_MAX_LENGTH_BYTES } from './constants'
export type WrappedConnection = ReturnType<typeof Wrap>; export type WrappedConnection = ReturnType<typeof Wrap>
type HandshakeParams = { interface HandshakeParams {
connection: WrappedConnection; connection: WrappedConnection
isInitiator: boolean; isInitiator: boolean
localPeer: PeerId; localPeer: PeerId
remotePeer?: PeerId; remotePeer?: PeerId
}; }
export class Noise implements INoiseConnection { export class Noise implements INoiseConnection {
public protocol = '/noise'; public protocol = '/noise'
private readonly prologue = Buffer.alloc(0); private readonly prologue = Buffer.alloc(0)
private readonly staticKeys: KeyPair; private readonly staticKeys: KeyPair
private readonly earlyData?: bytes; private readonly earlyData?: bytes
private useNoisePipes: boolean; private readonly useNoisePipes: boolean
/** /**
* *
@ -44,7 +44,7 @@ export class Noise implements INoiseConnection {
* @param {bytes} earlyData * @param {bytes} earlyData
*/ */
constructor (staticNoiseKey?: bytes, earlyData?: bytes) { constructor (staticNoiseKey?: bytes, earlyData?: bytes) {
this.earlyData = earlyData || Buffer.alloc(0) this.earlyData = earlyData ?? Buffer.alloc(0)
// disabled until properly specked // disabled until properly specked
this.useNoisePipes = false this.useNoisePipes = false
@ -71,9 +71,6 @@ export class Noise implements INoiseConnection {
const wrappedConnection = Wrap( const wrappedConnection = Wrap(
connection, connection,
{ {
// wrong types in repo
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
lengthEncoder: uint16BEEncode, lengthEncoder: uint16BEEncode,
lengthDecoder: uint16BEDecode, lengthDecoder: uint16BEDecode,
maxDataLength: NOISE_MSG_MAX_LENGTH_BYTES maxDataLength: NOISE_MSG_MAX_LENGTH_BYTES
@ -106,9 +103,6 @@ export class Noise implements INoiseConnection {
const wrappedConnection = Wrap( const wrappedConnection = Wrap(
connection, connection,
{ {
// wrong types in repo
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
lengthEncoder: uint16BEEncode, lengthEncoder: uint16BEEncode,
lengthDecoder: uint16BEDecode, lengthDecoder: uint16BEDecode,
maxDataLength: NOISE_MSG_MAX_LENGTH_BYTES maxDataLength: NOISE_MSG_MAX_LENGTH_BYTES
@ -153,7 +147,7 @@ export class Noise implements INoiseConnection {
this.staticKeys, this.staticKeys,
connection, connection,
// safe to cast as we did checks // safe to cast as we did checks
KeyCache.load(params.remotePeer) || Buffer.alloc(32), KeyCache.load(params.remotePeer) ?? Buffer.alloc(32),
remotePeer as PeerId remotePeer as PeerId
) )
@ -189,7 +183,8 @@ export class Noise implements INoiseConnection {
await handshake.finish() await handshake.finish()
} catch (e) { } catch (e) {
logger(e) logger(e)
throw new Error(`Error occurred during XX Fallback handshake: ${e.message}`) const err = e as Error
throw new Error(`Error occurred during XX Fallback handshake: ${err.message}`)
} }
return handshake return handshake
@ -211,7 +206,8 @@ export class Noise implements INoiseConnection {
KeyCache.store(handshake.remotePeer, handshake.getRemoteStaticKey()) KeyCache.store(handshake.remotePeer, handshake.getRemoteStaticKey())
} }
} catch (e) { } catch (e) {
throw new Error(`Error occurred during XX handshake: ${e.message}`) const err = e as Error
throw new Error(`Error occurred during XX handshake: ${err.message}`)
} }
return handshake return handshake

View File

@ -28,9 +28,9 @@ export async function getPayload (
earlyData?: bytes earlyData?: bytes
): Promise<bytes> { ): Promise<bytes> {
const signedPayload = await signPayload(localPeer, getHandshakePayload(staticPublicKey)) const signedPayload = await signPayload(localPeer, getHandshakePayload(staticPublicKey))
const earlyDataPayload = earlyData || Buffer.alloc(0) const earlyDataPayload = earlyData ?? Buffer.alloc(0)
return await createHandshakePayload( return createHandshakePayload(
localPeer.marshalPubKey(), localPeer.marshalPubKey(),
signedPayload, signedPayload,
earlyDataPayload earlyDataPayload
@ -45,7 +45,7 @@ export function createHandshakePayload (
const payloadInit = NoiseHandshakePayloadProto.create({ const payloadInit = NoiseHandshakePayloadProto.create({
identityKey: Buffer.from(libp2pPublicKey), identityKey: Buffer.from(libp2pPublicKey),
identitySig: signedPayload, identitySig: signedPayload,
data: earlyData || null data: earlyData ?? null
}) })
return Buffer.from(NoiseHandshakePayloadProto.encode(payloadInit).finish()) return Buffer.from(NoiseHandshakePayloadProto.encode(payloadInit).finish())
@ -94,10 +94,12 @@ export async function verifySignedPayload (
const generatedPayload = getHandshakePayload(noiseStaticKey) const generatedPayload = getHandshakePayload(noiseStaticKey)
// Unmarshaling from PublicKey protobuf // Unmarshaling from PublicKey protobuf
const publicKey = keys.unmarshalPublicKey(identityKey) const publicKey = keys.unmarshalPublicKey(identityKey)
// TODO remove this after libp2p-crypto ships proper types
// eslint-disable-next-line @typescript-eslint/no-misused-promises
if (!payload.identitySig || !publicKey.verify(generatedPayload, Buffer.from(payload.identitySig))) { if (!payload.identitySig || !publicKey.verify(generatedPayload, Buffer.from(payload.identitySig))) {
throw new Error("Static key doesn't match to peer that signed payload!") throw new Error("Static key doesn't match to peer that signed payload!")
} }
return PeerId.createFromPubKey(identityKey) return await PeerId.createFromPubKey(identityKey)
} }
export function getHkdf (ck: bytes32, ikm: bytes): Hkdf { export function getHkdf (ck: bytes32, ikm: bytes): Hkdf {

View File

@ -19,9 +19,9 @@ const peers = [{
pubKey: 'CAESIMbnikZaPciAMZhUXqDRVCs7VFOBtmlIk26g0GgOotDA' pubKey: 'CAESIMbnikZaPciAMZhUXqDRVCs7VFOBtmlIk26g0GgOotDA'
}] }]
export async function createPeerIdsFromFixtures (length:number): Promise<PeerId[]> { export async function createPeerIdsFromFixtures (length: number): Promise<PeerId[]> {
return await Promise.all( return await Promise.all(
Array.from({ length }).map((_, i) => PeerId.createFromJSON(peers[i])) Array.from({ length }).map(async (_, i) => await PeerId.createFromJSON(peers[i]))
) )
} }

View File

@ -56,8 +56,8 @@ describe('IK handshake', () => {
// initiator receives message // initiator receives message
ikI.recvMessage(initiatorSession, messageBuffer2) ikI.recvMessage(initiatorSession, messageBuffer2)
assert(initiatorSession?.cs1?.k.equals(responderSession?.cs1?.k || new Uint8Array())) assert(initiatorSession?.cs1?.k.equals(responderSession?.cs1?.k ?? new Uint8Array()))
assert(initiatorSession?.cs2?.k.equals(responderSession?.cs2?.k || new Uint8Array())) assert(initiatorSession?.cs2?.k.equals(responderSession?.cs2?.k ?? new Uint8Array()))
} catch (e) { } catch (e) {
return assert(false, e.message) return assert(false, e.message)
} }

View File

@ -15,9 +15,10 @@ describe('KeyCache', () => {
const key = Buffer.from('this is id 007') const key = Buffer.from('this is id 007')
await KeyCache.store(peerA, key) await KeyCache.store(peerA, key)
const result = await KeyCache.load(peerA) const result = await KeyCache.load(peerA)
assert(uint8ArrayEquals(result, key), 'Stored and loaded key are not the same') assert(result !== null && uint8ArrayEquals(result, key), 'Stored and loaded key are not the same')
} catch (e) { } catch (e) {
assert(false, `Test failed - ${e.message}`) const err = e as Error
assert(false, `Test failed - ${err.message}`)
} }
}) })
@ -25,9 +26,10 @@ describe('KeyCache', () => {
try { try {
const [newPeer] = await createPeerIds(1) const [newPeer] = await createPeerIds(1)
const result = await KeyCache.load(newPeer) const result = await KeyCache.load(newPeer)
assert(!result) assert(result === null)
} catch (e) { } catch (e) {
assert(false, `Test failed - ${e.message}`) const err = e as Error
assert(false, `Test failed - ${err.message}`)
} }
}) })
}) })

View File

@ -8,7 +8,7 @@ export async function generateEd25519Keys (): Promise<PrivateKey> {
export function getKeyPairFromPeerId (peerId: PeerId): KeyPair { export function getKeyPairFromPeerId (peerId: PeerId): KeyPair {
return { return {
privateKey: peerId.privKey.marshal().slice(0, 32), privateKey: Buffer.from(peerId.privKey.marshal().slice(0, 32)),
publicKey: peerId.marshalPubKey() publicKey: Buffer.from(peerId.marshalPubKey())
} }
} }

View File

@ -48,7 +48,7 @@ describe('XX Fallback Handshake', () => {
// This is the point where initiator falls back from IK // This is the point where initiator falls back from IK
const initialMsgI = await connectionFrom.readLP() const initialMsgI = await connectionFrom.readLP()
const handshakeInit = const handshakeInit =
new XXFallbackHandshake(true, handshakePayload, prologue, staticKeysInitiator, connectionFrom, initialMsgI, peerB, ephemeralKeys) new XXFallbackHandshake(true, handshakePayload, prologue, staticKeysInitiator, connectionFrom, initialMsgI.slice(0), peerB, ephemeralKeys)
await handshakeInit.propose() await handshakeInit.propose()
await handshakeInit.exchange() await handshakeInit.exchange()
@ -60,7 +60,10 @@ describe('XX Fallback Handshake', () => {
const sessionResponder = handshakeResp.session const sessionResponder = handshakeResp.session
// Test shared key // Test shared key
if (sessionInitator.cs1 && sessionResponder.cs1 && sessionInitator.cs2 && sessionResponder.cs2) { if (sessionInitator.cs1 !== undefined &&
sessionResponder.cs1 !== undefined &&
sessionInitator.cs2 !== undefined &&
sessionResponder.cs2 !== undefined) {
assert(sessionInitator.cs1.k.equals(sessionResponder.cs1.k)) assert(sessionInitator.cs1.k.equals(sessionResponder.cs1.k))
assert(sessionInitator.cs2.k.equals(sessionResponder.cs2.k)) assert(sessionInitator.cs2.k.equals(sessionResponder.cs2.k))
} else { } else {