ipsn/send.ts

119 lines
4.4 KiB
TypeScript
Raw Permalink Normal View History

2022-07-06 11:23:55 +00:00
import fs from "fs";
import crypto from "crypto";
import { encode } from "@msgpack/msgpack";
import CID from "cids";
import { create as IpfsClient } from "ipfs-client";
import Config, { Settings } from "./config.js";
import { Constants, DERToPEM } from "./constants.js";
/**
* Generate a keypair first using the following commands:
*
* openssl genpkey -algorithm ed25519 -outform DER -out ed25519-sign-private.der
* echo -e "-----BEGIN PRIVATE KEY-----\n$( cat ed25519-sign-private.der | base64 )\n-----END PRIVATE KEY-----" | openssl pkey -pubout -outform DER -out - > ed25519-sign-public.der
*
* Keys are stored in DER because easier to validate, but easier to use PEM in
* tools so they are converted on the fly.
*/
const data = JSON.parse(fs.readFileSync(process.argv[3], "utf8"));
const privateSigningKey = fs.readFileSync(Config.keys.sign.private);
const publicSigningKey = fs.readFileSync(Config.keys.sign.private);
let buffer = Buffer.alloc(Constants.fields.TOTAL_HEADERS_LENGTH);
Constants.fields.headers.forEach((def) => {
const print = (name: string, offset: number, value: number | string) => console.log(`Writing: ${name}, offset: ${offset}, value: ${value}`);
if (def.derived) {
if (def.name === "TIMESTAMP") {
const value = Math.floor(Date.now() / 1000);
print(def.name, def.offset, value);
buffer.writeUint32BE(value, def.offset);
}
}
else {
print(def.name, def.offset, data[def.name]);
if (def.length == 1) buffer.writeUint8(data[def.name], def.offset);
else if (def.length == 2) buffer.writeUint16BE(data[def.name], def.offset);
else if (def.length == 4) buffer.writeUint32BE(data[def.name], def.offset);
else console.log(`bad: ${def.name}, offset: ${def.offset}`);
}
});
console.log("preparing payload...");
if (data.PAYLOAD_TYPE == 1) {
console.log("Payload is a note.");
data.PAYLOAD.frm = publicSigningKey;
data.PAYLOAD.to = publicSigningKey;
if (data.PAYLOAD.sub) console.log(`Subject: \`${data.PAYLOAD.sub}\``);
if (data.PAYLOAD.msg) console.log(`Message: \`${data.PAYLOAD.msg}\``);
if (data.PAYLOAD.rply) {
const cid = new CID(data.PAYLOAD.rply);
data.PAYLOAD.rply = cid.bytes;
console.log("Converting reply IPFS CID to binary before encoding.");
}
if (data.PAYLOAD.img) {
const cid = new CID(data.PAYLOAD.img);
data.PAYLOAD.img = cid.bytes;
console.log("Converting image IPFS CID to binary before encoding.");
}
}
else {
console.log("Unknown payload type.");
process.exit(1);
}
const payload = Buffer.from(encode(data.PAYLOAD));
console.log("Encoded messagepack payload: " + payload.toString("hex"));
console.log(`Writing: PAYLOAD_LENGTH: offset: 14, value: ${payload.byteLength}`);
buffer.writeUint16BE(payload.byteLength, Constants.fields.PAYLOAD_LENGTH_OFFSET); // sorry hardcode
console.log(`Writing PAYLOAD: offset: ${buffer.byteLength}, value: (omitted)`);
// append the payload data.
buffer = Buffer.concat([buffer, payload]);
console.log("Generating Ed25519 signature of data...");
const signature = crypto.sign(null, buffer, DERToPEM(privateSigningKey));
buffer = Buffer.concat([buffer, signature]);
console.log(`Entire packet length: ${buffer.byteLength}`);
console.log("Writing to file: packet.dat");
fs.writeFileSync("packet.dat", buffer);
const listenSettings = <Settings>JSON.parse(fs.readFileSync("listen.json", "utf8"));
const options = listenSettings.nodes[process.argv[2]].options;
console.log(`Attempting to connect to: ${JSON.stringify(options)}`);
const ipfs = IpfsClient(options);
const channel = "ipsn-" + publicSigningKey.subarray(12).toString("hex");
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 === listenSettings.nodes[process.argv[2]].peers[0]) {
console.log("Already connected to remote peer");
connectedToPeer = true;
}
}
if (!connectedToPeer) {
console.log(`Attempting to connect to peer: ${listenSettings.nodes[process.argv[2]].peers[0]}`);
await ipfs.swarm.connect(listenSettings.nodes[process.argv[2]].peers[0]);
}
console.log(`Publishing to: ${channel}`);
await ipfs.pubsub.publish(channel, buffer);
process.exit(0);