2020-08-25 13:05:58 +02:00
|
|
|
'use strict'
|
|
|
|
|
|
|
|
const PeerId = require('peer-id')
|
|
|
|
const { Message } = require('./index')
|
|
|
|
const uint8ArrayConcat = require('uint8arrays/concat')
|
|
|
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
|
|
|
const SignPrefix = uint8ArrayFromString('libp2p-pubsub:')
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Signs the provided message with the given `peerId`
|
|
|
|
*
|
|
|
|
* @param {PeerId} peerId
|
|
|
|
* @param {Message} message
|
|
|
|
* @returns {Promise<Message>}
|
|
|
|
*/
|
|
|
|
async function signMessage (peerId, message) {
|
|
|
|
// Get the message in bytes, and prepend with the pubsub prefix
|
|
|
|
const bytes = uint8ArrayConcat([
|
|
|
|
SignPrefix,
|
|
|
|
Message.encode(message)
|
|
|
|
])
|
|
|
|
|
|
|
|
const signature = await peerId.privKey.sign(bytes)
|
|
|
|
|
|
|
|
return {
|
|
|
|
...message,
|
|
|
|
signature: signature,
|
|
|
|
key: peerId.pubKey.bytes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Verifies the signature of the given message
|
2020-12-01 12:24:51 +01:00
|
|
|
*
|
2020-08-25 13:05:58 +02:00
|
|
|
* @param {InMessage} message
|
2020-12-01 12:24:51 +01:00
|
|
|
* @returns {Promise<boolean>}
|
2020-08-25 13:05:58 +02:00
|
|
|
*/
|
|
|
|
async function verifySignature (message) {
|
|
|
|
// Get message sans the signature
|
|
|
|
const baseMessage = { ...message }
|
|
|
|
delete baseMessage.signature
|
|
|
|
delete baseMessage.key
|
2020-12-02 16:04:16 +01:00
|
|
|
|
2020-08-25 13:05:58 +02:00
|
|
|
const bytes = uint8ArrayConcat([
|
|
|
|
SignPrefix,
|
2020-12-02 16:04:16 +01:00
|
|
|
Message.encode(Object.assign(baseMessage, {
|
|
|
|
from: baseMessage.from && PeerId.createFromCID(baseMessage.from).toBytes()
|
|
|
|
}))
|
2020-08-25 13:05:58 +02:00
|
|
|
])
|
|
|
|
|
|
|
|
// Get the public key
|
|
|
|
const pubKey = await messagePublicKey(message)
|
|
|
|
|
|
|
|
// verify the base message
|
2020-12-02 01:33:13 -08:00
|
|
|
// @ts-ignore - may not have signature
|
2020-08-25 13:05:58 +02:00
|
|
|
return pubKey.verify(bytes, message.signature)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the PublicKey associated with the given message.
|
|
|
|
* If no, valid PublicKey can be retrieved an error will be returned.
|
|
|
|
*
|
|
|
|
* @param {InMessage} message
|
|
|
|
* @returns {Promise<PublicKey>}
|
|
|
|
*/
|
|
|
|
async function messagePublicKey (message) {
|
|
|
|
// should be available in the from property of the message (peer id)
|
2020-12-02 16:04:16 +01:00
|
|
|
// @ts-ignore - from type changed
|
2020-08-25 13:05:58 +02:00
|
|
|
const from = PeerId.createFromCID(message.from)
|
|
|
|
|
|
|
|
if (message.key) {
|
|
|
|
const keyPeerId = await PeerId.createFromPubKey(message.key)
|
|
|
|
|
|
|
|
// the key belongs to the sender, return the key
|
2020-12-02 16:04:16 +01:00
|
|
|
if (keyPeerId.equals(from)) return keyPeerId.pubKey
|
2020-08-25 13:05:58 +02:00
|
|
|
// We couldn't validate pubkey is from the originator, error
|
|
|
|
throw new Error('Public Key does not match the originator')
|
|
|
|
} else if (from.pubKey) {
|
|
|
|
return from.pubKey
|
|
|
|
} else {
|
|
|
|
throw new Error('Could not get the public key from the originator id')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-02 01:33:13 -08:00
|
|
|
/**
|
|
|
|
* @typedef {import('..').InMessage} InMessage
|
|
|
|
* @typedef {import('libp2p-crypto').PublicKey} PublicKey
|
|
|
|
*/
|
|
|
|
|
2020-08-25 13:05:58 +02:00
|
|
|
module.exports = {
|
|
|
|
messagePublicKey,
|
|
|
|
signMessage,
|
|
|
|
SignPrefix,
|
|
|
|
verifySignature
|
|
|
|
}
|