Stefan 17c7e46917 feat(wallet) Wallet Connect: process delete_session
Requires the specific status-go changes that brings WCChangePairingState

Process delete session and update internal pairing history state

Updated testing while fighting for the issue of not deleting the session
Found out that the client requests a different topic in the delete
session request.

Also:

- update debugging UX to support session events
- update storybook to support mocking session events
- fix go test utility to account for refactoring

Updates #12858
2023-11-30 10:47:41 +01:00

384 lines
15 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Wallet Connect status-go test</title>
<style></style>
</head>
<body>
<div id="log"></div>
<script src="bundle.js" type="module"></script>
<script>
// Helper functions
//
function goEcho(message) {
window.echo(message);
}
// If not null add to it
var logEntries = null;
var newSessionButton;
var hashedPasswordInput;
function addHtmlEntry(htmlContent, color = null, entry = null) {
const logDiv = document.getElementById("log");
if (entry) {
entry.remove();
}
entry = document.createElement("div");
logDiv.appendChild(entry);
entry.innerHTML = htmlContent;
if (color) {
entry.style.color = color;
}
entry.scrollIntoView();
if (logEntries) {
logEntries.push(entry);
}
return entry;
}
function addLogEntry(message, color = "black", entry = null) {
return addHtmlEntry(`${message}`, color, entry);
}
function logComponentStatusChange(componentName, statusMessage, color = "black", entry = null) {
const componentHtml = `<span style="color: fuchsia;">${componentName}</span>: `;
const statusHtml = `<span style="color: ${color};">${statusMessage}</span>`;
return addHtmlEntry(`${componentHtml}${statusHtml}`, null, entry);
}
// SDK initialization
//
const statusGoEntry = logComponentStatusChange("status-go", "Initializing...");
var initEventCount = 0;
var eventCount = 0;
const readyToPairEventName = "readyToPair";
async function initializeSDK() {
try {
const sdkEntry = logComponentStatusChange("SDK", "Initializing...");
const conf = await window.getConfiguration();
await window.wc.init(conf.projectId);
logComponentStatusChange("SDK", "Initialized", "green", sdkEntry);
initEventCount++;
} catch (error) {
goEcho(`SDK init error: ${error}`);
logComponentStatusChange("SDK", "FAIL initializing ${error}", "red", sdkEntry);
}
}
// Simulate statusObject
window.statusq = {
channel: {
objects: {
statusObject: {
sdkInitialized: function (error) {
window.statusObject_sdkInitialized(error);
},
onSessionProposal: function (sessionProposal) {
window.statusObject_onSessionProposal(JSON.stringify(sessionProposal)).then((success) => {
if (!success) {
goEcho(`statusObject: onSessionProposal call failed ${sessionProposal.id}`);
return;
}
});
},
onSessionRequest: function (sessionRequest) {
eventCount++;
logComponentStatusChange("SDK", `received "session_request" event`, "green");
addLogEntry(`Data: ${JSON.stringify(sessionRequest)}`);
addHtmlEntry(
`<button id="acceptSessionButton${eventCount}">Accept</button> <button id="rejectSessionButton${eventCount}">Reject</button>`
);
const acceptSessionButton = document.getElementById(`acceptSessionButton${eventCount}`);
const rejectSessionButton = document.getElementById(`rejectSessionButton${eventCount}`);
acceptSessionButton.addEventListener("click", function () {
const sessionReqEntry = logComponentStatusChange("status-go", `sessionRequest called`, "orange");
window.sessionRequest(JSON.stringify(sessionRequest), hashedPasswordInput.value).then((success) => {
acceptSessionButton.disabled = true;
rejectSessionButton.disabled = true;
if (success) {
logComponentStatusChange("status-go", `sessionRequest OK`, "green", sessionReqEntry);
// waiting for "sessionRequestResult" event
} else {
logComponentStatusChange(
"status-go",
`sessionRequest call failed for topic ${sessionRequest.topic}`,
"red",
sessionReqEntry
);
window.wc.rejectSessionRequest(sessionRequest.topic, sessionRequest.id, true);
setStatus(`Session ${sessionRequest.id} rejected, internal error`, "purple");
}
});
});
rejectSessionButton.addEventListener("click", function () {
acceptSessionButton.disabled = true;
rejectSessionButton.disabled = true;
window.wc.rejectSessionRequest(sessionRequest.topic, sessionRequest.id).then(
() => {
addLogEntry(`Session ${sessionRequest.id} rejected`);
},
(err) => {
addLogEntry(`Session ${sessionRequest.id} reject error: ${err.message}`, "red");
}
);
});
},
onSessionDelete: function (deletePayload) {
goEcho(`statusObject: onSessionDelete ${JSON.stringify(deletePayload)}`);
},
onSessionExpire: function (expirePayload) {
goEcho(`statusObject: onSessionExpire ${JSON.stringify(expirePayload)}`);
},
onSessionUpdate: function (updatePayload) {
goEcho(`statusObject: onSessionUpdate ${JSON.stringify(updatePayload)}`);
},
onSessionExtend: function (extendPayload) {
goEcho(`statusObject: onSessionExtend ${JSON.stringify(extendPayload)}`);
},
onSessionPing: function (pingPayload) {
goEcho(`statusObject: onSessionPing ${JSON.stringify(pingPayload)}`);
},
onSessionEvent: function (eventPayload) {
goEcho(`statusObject: onSessionEvent ${JSON.stringify(eventPayload)}`);
},
onSessionRequest: function (sessionRequestPayload) {
goEcho(`statusObject: onSessionRequest ${JSON.stringify(sessionRequestPayload)}`);
},
onSessionRequestSent: function (sessionRequestSentPayload) {
goEcho(`statusObject: onSessionRequestSent ${JSON.stringify(sessionRequestSentPayload)}`);
},
onProposalExpire: function (proposalExpirePayload) {
goEcho(`statusObject: onProposalExpire ${JSON.stringify(proposalExpirePayload)}`);
},
},
},
},
};
var pairLinkInput = null;
var pairButton = null;
function newPairWorkflow() {
// Remove all the previous entries
if (logEntries) {
for (let i = 0; i < logEntries.length; i++) {
logEntries[i].remove();
}
}
logEntries = [];
eventCount++;
// Add session reset and password input
addHtmlEntry(`<button id="newSessionButton" style="display: none;">New Session</button>`);
newSessionButton = document.getElementById("newSessionButton");
newSessionButton.addEventListener("click", function () {
newPairWorkflow();
});
addHtmlEntry(
`<input type="text" id="hashedPasswordInput" placeholder="Insert hashed password" value="0x38301fb0b5fcf3aaa4b97c4771bb6c75546e313b4ce7057c51a8cc6a3ace9d7e"/>`
);
hashedPasswordInput = document.getElementById(`hashedPasswordInput`);
addHtmlEntry(
`<input type="text" id="pairLinkInput" placeholder="Insert pair link" /><button id="pairButton" disabled>Pair</button>`
);
// List existing pairing sessions
const pairingsRes = window.wc.getPairings();
let pairings = [];
if (pairingsRes) {
if (!!pairingsRes.error) {
goEcho(`getPairings() error: ${pairingsRes.error}`);
return;
} else if (pairingsRes.result) {
pairings = pairingsRes.result;
}
}
if (pairings.length > 0) {
addHtmlEntry(`Existing pairings:`, "fuchsia");
}
for (let i = 0; i < pairings.length; i++) {
const p = pairings[i];
const disconnectEntry = addHtmlEntry(
`[${i + 1}] <span style="color: ${p.active ? "green" : "orange"};">${
p.active ? "ACTIVE" : "INACTIVE"
}</span> <span class="elide-text">${p.topic}</span>; Expires: ${timestampToStr(
p.expiry
)} <button id="unpairButton${i}">Disconnect</button>`
);
const unpairButton = document.getElementById(`unpairButton${i}`);
unpairButton.addEventListener("click", function () {
const res = window.wc.disconnect(p.topic);
if (res && !!res.error) {
addLogEntry(`Pairing ${p.topic} disconnect error: ${err.message}`, "red", disconnectEntry);
return;
}
addLogEntry(`Pairing ${p.topic} disconnected`, "green", disconnectEntry);
unpairButton.remove();
});
}
// Add pairing options
pairLinkInput = document.getElementById(`pairLinkInput`);
pairButton = document.getElementById(`pairButton`);
pairLinkInput.addEventListener("input", function () {
pairButton.disabled = !(pairLinkInput.value.length > 0);
});
pairButton.addEventListener("click", function () {
newSessionButton.style.display = "inline";
pairButton.disabled = true;
pairLinkInput.disabled = true;
const sdkEntry = logComponentStatusChange("SDK", "Pairing...");
const result = window.wc.pair(pairLinkInput.value);
if (result && !!result.error) {
goEcho("pair() error: ", result.error);
logComponentStatusChange("SDK", `Pairing error ${error.message}`, "red", sdkEntry);
return;
}
logComponentStatusChange("SDK", "got Pair session proposal", "green", sdkEntry);
const goSessionEntry = logComponentStatusChange("GO.pairSessionProposal", "waiting status-go", "pink");
});
}
document.addEventListener(`proposeUserPair`, function (event) {
logComponentStatusChange("GO.proposeUserPair", `received "proposeUserPair"`, "green");
addLogEntry(JSON.stringify(event.detail.supportedNamespaces));
if (!document.getElementById(`acceptPairButton`)) {
addHtmlEntry(`<button id="acceptPairButton">Accept</button><button id="rejectPairButton">Reject</button>`);
}
const acceptPairButton = document.getElementById(`acceptPairButton`);
const rejectPairButton = document.getElementById(`rejectPairButton`);
const sessionProposal = event.detail.sessionProposal;
acceptPairButton.addEventListener("click", function () {
const result = window.wc.approvePairSession(sessionProposal, event.detail.supportedNamespaces);
if (result && !!result.error) {
logComponentStatusChange(
"GO.pairSessionProposal",
`Pair session ${sessionProposal.id} approve error: ${result.error}`,
"red",
goSessionEntry
);
return;
}
acceptPairButton.remove();
rejectPairButton.remove();
root.controller_recordSuccessfulPairing(JSON.stringify(sessionProposal));
logComponentStatusChange(
"GO.pairSessionProposal",
`Pair session ${sessionProposal.id} approved`,
"green",
goSessionEntry
);
});
rejectPairButton.addEventListener("click", function () {
const result = window.wc.rejectPairSession(sessionProposal.id);
if (result && !!result.error) {
logComponentStatusChange(
"GO.pairSessionProposal",
`Pair session ${sessionProposal.id} reject error: ${result.error}`,
"red",
goSessionEntry
);
return;
}
acceptPairButton.remove();
rejectPairButton.remove();
logComponentStatusChange(
"GO.pairSessionProposal",
`Pair session ${sessionProposal.id} rejected`,
"green",
goSessionEntry
);
});
});
document.addEventListener("sessionRequestResult", function (event) {
let req = event.detail.sessionRequest;
const res = window.wc.respondSessionRequest(req.topic, req.id, event.detail.signed);
addLogEntry(`Session ${req.topic} approval accepted`);
addHtmlEntry(
`</br><a href="https://goerli.etherscan.io/tx/${event.detail.signed}" target="_blank">${event.detail.signed}</a>`
);
});
// Add start from scratch option
document.addEventListener(readyToPairEventName, function () {
newPairWorkflow();
});
async function processGoEvents() {
while (true) {
try {
const event = await window.popNextEvent();
switch (event.name) {
case "nodeReady":
logComponentStatusChange("status-go", "Ready", "green", statusGoEntry);
initEventCount++;
break;
default:
// Handle status-go and SDK bootstrap events
if (initEventCount == 2) {
initEventCount++;
document.dispatchEvent(new CustomEvent(readyToPairEventName, {}));
} else if (event.name != "") {
goEcho(`GO event: ${event.name}`);
document.dispatchEvent(new CustomEvent(event.name, { detail: event.payload }));
} else {
await new Promise((resolve) => setTimeout(resolve, 100));
}
break;
}
} catch (err) {
goEcho(`GO event error: ${err.message}`);
}
}
}
processGoEvents();
// Call the initializeSDK function on page load
window.addEventListener("DOMContentLoaded", (event) => {
initializeSDK();
});
function timestampToStr(timestamp) {
const date = new Date(timestamp * 1000);
const readableDate = date.toLocaleDateString();
const readableTime = date.toLocaleTimeString();
return `${readableDate} - ${readableTime}`;
}
</script>
</body>
<style>
.elide-text {
max-width: 100px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
transition: max-width 0.3s ease;
vertical-align: middle;
}
.elide-text:hover {
max-width: none;
background-color: #f0f0f0;
z-index: 1;
position: relative;
}
</style>
</html>