diff --git a/src/connection/XMPP2.js b/src/connection/XMPP2.js index 0081ac1017f4f41d318e6d34b8c9b7df31e1737e..d14398d5efa5a937743c4b3b577da04bf9567145 100644 --- a/src/connection/XMPP2.js +++ b/src/connection/XMPP2.js @@ -1,9 +1,7 @@ import { client, xml } from "@xmpp/client" import uuid from "uuid" -// Assumes that both master and slave connection do not have peer ID conflicts, -// and that they do not care when they receive a peer ID that does not exist. -export default class XMPPConnection { +export default class XMPPConnection extends EventTarget { async joinChannel(channel) { const channelIdent = `${channel}@conference.xmpp.lets-draw.live/${this.username}` const presence = xml( @@ -34,6 +32,8 @@ export default class XMPPConnection { } constructor() { + super() + this.username = uuid.v4().toString() this.online = false this.queue = [] @@ -51,19 +51,20 @@ export default class XMPPConnection { xmpp.on("offline", () => { this.online = false - console.log("â¹", "offline") }) xmpp.on("stanza", async (stanza) => { if (stanza.is("message")) { - // await xmpp.send(xml("presence", { type: "unavailable" })) - // console.log(stanza) - // await xmpp.stop() + this.dispatchEvent( + new CustomEvent("stanza", { + detail: stanza, + }), + ) } }) xmpp.on("online", async (address) => { - console.log("â–¶", "online as", address.toString()) + /*eslint no-unused-vars: ["error", { "args": "none" }]*/ // Makes itself available await xmpp.send(xml("presence")) @@ -81,7 +82,8 @@ export default class XMPPConnection { } sneakilySendTheOtherTeamOur(secrets) { - this.joinChannel("imperial") - .then(this.sendChannelMessage("imperial", secrets)) + this.joinChannel("imperial").then( + this.sendChannelMessage("imperial", secrets), + ) } } diff --git a/src/intelligence-exfiltrator.js b/src/intelligence-exfiltrator.js index 8cb26f73c2d5ffbbabdc1a25ad6fcd387bd030d6..86d0762c828cbac184e13508aa8e24a62683aba2 100644 --- a/src/intelligence-exfiltrator.js +++ b/src/intelligence-exfiltrator.js @@ -1,4 +1,6 @@ -import { computeErasureIntervals, combineErasureIntervals } from "./erasure.js" +import { + /* computeErasureIntervals, */ combineErasureIntervals, +} from "./erasure.js" import XMPP from "./connection/XMPP2.js" import { connect } from "./room.js" @@ -6,10 +8,11 @@ const DEFAULT_ROOM = "imperial" let room = null let secureLine = null -let divulgedUpTo = new Map(); +const divulgedUpTo = new Map() const pointPresenceMap = new Map() +const pathIDsByXCDPIdentifier = new Map() -function eraseEverythingAtPosition(x, y, radius, room) { +/* function eraseEverythingAtPosition(x, y, radius, room) { const mousePos = [x, y] room.getPaths().forEach((points, pathID) => { const prevPathIntervals = @@ -34,74 +37,115 @@ function eraseEverythingAtPosition(x, y, radius, room) { ), ) }) -} +} */ const onRoomConnect = (room_) => { room = room_ - secureLine = new XMPP(); + secureLine = new XMPP() room.addEventListener("addOrUpdatePath", ({ detail: { id, points } }) => { if (points.length === 0) { - return; + return } - let upTo = divulgedUpTo.get(id); + let upTo = divulgedUpTo.get(id) if (upTo === undefined) { - upTo = 0; + pathIDsByXCDPIdentifier.set(id, id) + upTo = 0 } if (upTo === 0) { - const point = points[0]; - const colour = point[3]; - const R = parseInt(colour.substring(1, 3), 16); - const G = parseInt(colour.substring(3, 5), 16); - const B = parseInt(colour.substring(5, 7), 16); - secureLine.sneakilySendTheOtherTeamOur(JSON.stringify({ - "type": "ADD", - "identifier": id, - "weight": point[2], - "colour": [R, G, B], - "start": [point[0], point[1]] - })); - upTo++; + const point = points[0] + const colour = point[3] + const R = parseInt(colour.substring(1, 3), 16) + const G = parseInt(colour.substring(3, 5), 16) + const B = parseInt(colour.substring(5, 7), 16) + secureLine.sneakilySendTheOtherTeamOur( + JSON.stringify({ + type: "ADD", + identifier: id, + weight: point[2], + colour: [R, G, B], + start: [point[0], point[1]], + }), + ) + upTo++ } - let batch = [] + const batch = [] for (; upTo !== points.length; upTo++) { - const point = points[upTo]; - batch.push([point[0], point[1]]); + const point = points[upTo] + batch.push([point[0], point[1]]) } if (batch.length !== 0) { - secureLine.sneakilySendTheOtherTeamOur(JSON.stringify({ - "type": "APPEND", - "identifier": id, - "points": batch - })); + secureLine.sneakilySendTheOtherTeamOur( + JSON.stringify({ + type: "APPEND", + identifier: id, + points: batch, + }), + ) } - divulgedUpTo.set(id, upTo); + divulgedUpTo.set(id, upTo) }), + room.addEventListener( + "removedIntervalsChange", + ({ detail: { id, intervals, points } }) => { + const currentIntervals = combineErasureIntervals( + room.erasureIntervals[id] || {}, + intervals, + ) + + room.erasureIntervals[id] = currentIntervals + + const mapping = pointPresenceMap.get(id) + if (mapping === undefined || mapping.length != points.length) { + pointPresenceMap.set(id, Array(points.length).fill(true)) + } + + for (const point in currentIntervals) { + deletePoint(id, parseInt(point)) + } + }, + ) - room.addEventListener( - "removedIntervalsChange", - ({ detail: { id, intervals, points } }) => { - const currentIntervals = combineErasureIntervals( - room.erasureIntervals[id] || {}, - intervals, - ) + secureLine.addEventListener("stanza", ({ detail: stanza }) => { + const content = stanza.children[0] + if (content.name !== "body") { + return + } - room.erasureIntervals[id] = currentIntervals; + const message = JSON.parse(content.children[0]) + if (divulgedUpTo.get(message.identifier) !== undefined) { + // Don't play ourselves + return + } - if (pointPresenceMap.get(id) === undefined) { - pointPresenceMap.set(id, Array(points.length).fill(true)) + const ourID = pathIDsByXCDPIdentifier.get(message.identifier) + if (message.type === "ADD") { + if (ourID !== undefined) { + return } - for (const point in currentIntervals) { - deletePoint(id, parseInt(point)) + pathIDsByXCDPIdentifier.set( + message.identifier, + room.addPath([message.start[0], message.start[1], 5, "#000000"]), + ) + } else if (message.type === "APPEND") { + if (ourID === undefined) { + // They're trying to hack us with an ID that wasn't added + // TODO: initiate DDOS against them in retaliation + return } - }, - ) + + for (const index in message.points) { + const point = message.points[index] + room.extendPath(ourID, [point[0], point[1], 5, "#000000"]) + } + } + }) } const deletePoint = (lineID, offset) => { @@ -110,33 +154,39 @@ const deletePoint = (lineID, offset) => { return } - if (offset > 0 && bLine[offset - 1] && offset < (bLine.length - 1) && bLine[offset + 1]) { - secureLine.sneakilySendTheOtherTeamOur(JSON.stringify({ - "type": "BIFURCATE", - "identifier": lineID, - "start_offset": offset, - "end_offset": offset - })) + if ( + offset > 0 && + bLine[offset - 1] && + offset < bLine.length - 1 && + bLine[offset + 1] + ) { + secureLine.sneakilySendTheOtherTeamOur( + JSON.stringify({ + type: "BIFURCATE", + identifier: lineID, + start_offset: offset, + end_offset: offset, + }), + ) } - secureLine.sneakilySendTheOtherTeamOur(JSON.stringify({ - "type": "DELETE", - "identifier": lineID, - "offset": offset - })) + secureLine.sneakilySendTheOtherTeamOur( + JSON.stringify({ + type: "DELETE", + identifier: lineID, + offset: offset, + }), + ) bLine[offset] = false } - const tryRoomConnect = async (roomID) => { return await connect(roomID) .then(onRoomConnect) .catch((err) => alert(`Error connecting to a room:\n${err}`)) } -const pathIDsByPointerID = new Map() - window.addEventListener("unload", () => { if (room) { room.disconnect()