ipsn/listen.ts

90 lines
3.4 KiB
TypeScript
Raw Normal View History

2022-07-06 11:23:55 +00:00
import fs from "fs";
import crypto from "crypto";
import { create as IpfsClient } from "ipfs-client";
import { Message } from "@libp2p/interfaces/pubsub";
import { decode } from "@msgpack/msgpack";
import CID from "cids";
import Config, { Settings } from "./config.js";
import { Constants, DERToPEM } from "./constants";
const settings = <Settings>JSON.parse(fs.readFileSync("listen.json", "utf8"));
const options = settings.nodes[process.argv[2]].options;
console.log(`Attempting to connect to: ${JSON.stringify(options, null, 4)}`);
const ipfs = IpfsClient(options);
console.log("Querying server ID...");
const { id, agentVersion } = await ipfs.id();
console.log(`Connected to server: ${id} agent: ${agentVersion}`);
let connectedToPeer = false;
const peers = await ipfs.swarm.peers();
for (const peer of peers) {
const fullAddr = `${peer.addr}/ipfs/${peer.peer.toString()}`;
if (fullAddr === settings.nodes[process.argv[2]].peers[0]) {
console.log("Already connected to remote peer");
connectedToPeer = true;
}
}
if (!connectedToPeer) {
console.log(`Attempting to connect to remote peer: ${settings.nodes[process.argv[2]].peers[0]}`);
await ipfs.swarm.connect(settings.nodes[process.argv[2]].peers[0]);
}
const publicSigningKey = fs.readFileSync(Config.keys.sign.public);
const publicKey = publicSigningKey.subarray(Constants.crypto.PUBLIC_KEY_LENGTH - Constants.crypto.RAW_KEY_LENGTH).toString("hex");
const channel = `ipsn-${publicKey}`;
console.log(`Subscribing to: ${channel}`)
await ipfs.pubsub.subscribe(channel, (msg: Message) => {
if (id.equals(msg.from)) {
console.log("Ignoring message from self.");
}
else {
console.log("Received message!");
const buffer = Buffer.from(msg.data);
const payloadLength = buffer.readUint16BE(Constants.fields.PAYLOAD_LENGTH_OFFSET);
const payload = buffer.subarray(Constants.fields.PAYLOAD_OFFSET, Constants.fields.PAYLOAD_OFFSET + payloadLength);
console.log(`Payload size: ${payload.byteLength}`);
const msgpack = <Record<string, any>>decode(payload);
const from = Buffer.from(msgpack.frm);
try {
msgpack.rply = "ipfs://"+new CID(msgpack.rply).toString();
msgpack.frm = msgpack.frm.toString("hex");
msgpack.to = msgpack.to.toString("hex");
if (msgpack.img) msgpack.img = "ipfs://" + new CID(msgpack.img).toString();
}
catch(e) {
console.error("Error parsing message", e);
return;
}
console.log(msgpack);
const signablePortion = buffer.subarray(0, Constants.fields.PAYLOAD_OFFSET + payloadLength);
const signature = buffer.subarray(Constants.fields.PAYLOAD_OFFSET + payloadLength);
console.log(`signature length: ${signature.byteLength}`);
const isFromChannelOwner = ("ipsn-" + from.toString("hex")) === channel;
console.log(`Message from channel owner? ${isFromChannelOwner}`);
try {
// const senderPublicKey = Buffer.concat([publicKeyHeader, from]);
const senderPublicKey = DERToPEM(from);
const verified = crypto.verify(null, signablePortion, senderPublicKey, signature);
console.log(`Message signature verified? ${verified}`);
}
catch (e) {
console.error("error verifying message signature.", e);
}
}
});