Files
element-call-custom/src/settings/rageshake.js
Michael Kaye 5e42881c5c Rename groupcall.txt -> groupcall.json.
This will stop groupcall.txt being handled as a 'log file' and instead
indicate it's an artifact to be stored alongside the rageshake.

The file will still be stored on the rageshake server but the extension
will indicate it's not a log file.
2022-02-07 15:28:46 +00:00

283 lines
8.2 KiB
JavaScript

import { useCallback, useContext, useEffect, useState } from "react";
import * as rageshake from "matrix-react-sdk/src/rageshake/rageshake";
import pako from "pako";
import { useClient } from "../ClientContext";
import { InspectorContext } from "../room/GroupCallInspector";
import { useModalTriggerState } from "../Modal";
export function useSubmitRageshake() {
const { client } = useClient();
const [{ json }] = useContext(InspectorContext);
const [{ sending, sent, error }, setState] = useState({
sending: false,
sent: false,
error: null,
});
const submitRageshake = useCallback(
async (opts) => {
if (sending) {
return;
}
try {
setState({ sending: true, sent: false, error: null });
let userAgent = "UNKNOWN";
if (window.navigator && window.navigator.userAgent) {
userAgent = window.navigator.userAgent;
}
let touchInput = "UNKNOWN";
try {
// MDN claims broad support across browsers
touchInput = String(window.matchMedia("(pointer: coarse)").matches);
} catch (e) {}
const body = new FormData();
body.append(
"text",
opts.description || "User did not supply any additional text."
);
body.append("app", "matrix-video-chat");
body.append("version", "dev");
body.append("user_agent", userAgent);
body.append("installed_pwa", false);
body.append("touch_input", touchInput);
if (client) {
body.append("user_id", client.credentials.userId);
body.append("device_id", client.deviceId);
if (client.isCryptoEnabled()) {
const keys = [`ed25519:${client.getDeviceEd25519Key()}`];
if (client.getDeviceCurve25519Key) {
keys.push(`curve25519:${client.getDeviceCurve25519Key()}`);
}
body.append("device_keys", keys.join(", "));
body.append("cross_signing_key", client.getCrossSigningId());
// add cross-signing status information
const crossSigning = client.crypto.crossSigningInfo;
const secretStorage = client.crypto.secretStorage;
body.append(
"cross_signing_ready",
String(await client.isCrossSigningReady())
);
body.append(
"cross_signing_supported_by_hs",
String(
await client.doesServerSupportUnstableFeature(
"org.matrix.e2e_cross_signing"
)
)
);
body.append("cross_signing_key", crossSigning.getId());
body.append(
"cross_signing_privkey_in_secret_storage",
String(
!!(await crossSigning.isStoredInSecretStorage(secretStorage))
)
);
const pkCache = client.getCrossSigningCacheCallbacks();
body.append(
"cross_signing_master_privkey_cached",
String(
!!(pkCache && (await pkCache.getCrossSigningKeyCache("master")))
)
);
body.append(
"cross_signing_self_signing_privkey_cached",
String(
!!(
pkCache &&
(await pkCache.getCrossSigningKeyCache("self_signing"))
)
)
);
body.append(
"cross_signing_user_signing_privkey_cached",
String(
!!(
pkCache &&
(await pkCache.getCrossSigningKeyCache("user_signing"))
)
)
);
body.append(
"secret_storage_ready",
String(await client.isSecretStorageReady())
);
body.append(
"secret_storage_key_in_account",
String(!!(await secretStorage.hasKey()))
);
body.append(
"session_backup_key_in_secret_storage",
String(!!(await client.isKeyBackupKeyStored()))
);
const sessionBackupKeyFromCache =
await client.crypto.getSessionBackupPrivateKey();
body.append(
"session_backup_key_cached",
String(!!sessionBackupKeyFromCache)
);
body.append(
"session_backup_key_well_formed",
String(sessionBackupKeyFromCache instanceof Uint8Array)
);
}
}
if (opts.label) {
body.append("label", opts.label);
}
// add storage persistence/quota information
if (navigator.storage && navigator.storage.persisted) {
try {
body.append(
"storageManager_persisted",
String(await navigator.storage.persisted())
);
} catch (e) {}
} else if (document.hasStorageAccess) {
// Safari
try {
body.append(
"storageManager_persisted",
String(await document.hasStorageAccess())
);
} catch (e) {}
}
if (navigator.storage && navigator.storage.estimate) {
try {
const estimate = await navigator.storage.estimate();
body.append("storageManager_quota", String(estimate.quota));
body.append("storageManager_usage", String(estimate.usage));
if (estimate.usageDetails) {
Object.keys(estimate.usageDetails).forEach((k) => {
body.append(
`storageManager_usage_${k}`,
String(estimate.usageDetails[k])
);
});
}
} catch (e) {}
}
if (opts.sendLogs) {
const logs = await rageshake.getLogsForReport();
for (const entry of logs) {
// encode as UTF-8
let buf = new TextEncoder().encode(entry.lines);
// compress
buf = pako.gzip(buf);
body.append("compressed-log", new Blob([buf]), entry.id);
}
if (json) {
body.append(
"file",
new Blob([JSON.stringify(json)], { type: "text/plain" }),
"groupcall.json"
);
}
}
await fetch(
import.meta.env.VITE_RAGESHAKE_SUBMIT_URL ||
"https://element.io/bugreports/submit",
{
method: "POST",
body,
}
);
setState({ sending: false, sent: true, error: null });
} catch (error) {
setState({ sending: false, sent: false, error });
console.error(error);
}
},
[client]
);
return {
submitRageshake,
sending,
sent,
error,
};
}
export function useDownloadDebugLog() {
const [{ json }] = useContext(InspectorContext);
const downloadDebugLog = useCallback(() => {
const blob = new Blob([JSON.stringify(json)], { type: "application/json" });
const url = URL.createObjectURL(blob);
const el = document.createElement("a");
el.href = url;
el.download = "groupcall.json";
el.style.display = "none";
document.body.appendChild(el);
el.click();
setTimeout(() => {
URL.revokeObjectURL(url);
el.parentNode.removeChild(el);
}, 0);
}, [json]);
return downloadDebugLog;
}
export function useRageshakeRequest() {
const { client } = useClient();
const sendRageshakeRequest = useCallback(
(roomId) => {
client.sendEvent(roomId, "org.matrix.rageshake_request", {});
},
[client]
);
return sendRageshakeRequest;
}
export function useRageshakeRequestModal(roomId) {
const { modalState, modalProps } = useModalTriggerState();
const { client } = useClient();
useEffect(() => {
const onEvent = (event) => {
const type = event.getType();
if (
type === "org.matrix.rageshake_request" &&
roomId === event.getRoomId() &&
client.getUserId() !== event.getSender()
) {
modalState.open();
}
};
client.on("event", onEvent);
return () => {
client.removeListener("event", onEvent);
};
}, [modalState.open, roomId]);
return { modalState, modalProps };
}