90 lines
3.4 KiB
TypeScript
90 lines
3.4 KiB
TypeScript
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);
|
|
}
|
|
|
|
}
|
|
});
|