Add rageshake submit state
This commit is contained in:
parent
76b2e8b29e
commit
8ab68ed8c8
2 changed files with 201 additions and 170 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import { Modal } from "../Modal";
|
import { Modal } from "../Modal";
|
||||||
import styles from "./SettingsModal.module.css";
|
import styles from "./SettingsModal.module.css";
|
||||||
import { TabContainer, TabItem } from "../tabs/Tabs";
|
import { TabContainer, TabItem } from "../tabs/Tabs";
|
||||||
|
|
@ -8,7 +8,7 @@ import { ReactComponent as DeveloperIcon } from "../icons/Developer.svg";
|
||||||
import { SelectInput } from "../input/SelectInput";
|
import { SelectInput } from "../input/SelectInput";
|
||||||
import { Item } from "@react-stately/collections";
|
import { Item } from "@react-stately/collections";
|
||||||
import { useMediaHandler } from "./useMediaHandler";
|
import { useMediaHandler } from "./useMediaHandler";
|
||||||
import { FieldRow, InputField } from "../input/Input";
|
import { FieldRow, InputField, ErrorMessage } from "../input/Input";
|
||||||
import { Button } from "../button";
|
import { Button } from "../button";
|
||||||
import { useSubmitRageshake } from "./useSubmitRageshake";
|
import { useSubmitRageshake } from "./useSubmitRageshake";
|
||||||
|
|
||||||
|
|
@ -27,7 +27,8 @@ export function SettingsModal({
|
||||||
setVideoInput,
|
setVideoInput,
|
||||||
} = useMediaHandler(client);
|
} = useMediaHandler(client);
|
||||||
|
|
||||||
const { submitRageshake, downloadDebugLog } = useSubmitRageshake();
|
const { submitRageshake, sending, sent, error, downloadDebugLog } =
|
||||||
|
useSubmitRageshake();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
|
@ -93,8 +94,19 @@ export function SettingsModal({
|
||||||
/>
|
/>
|
||||||
</FieldRow>
|
</FieldRow>
|
||||||
<FieldRow>
|
<FieldRow>
|
||||||
<Button onPress={submitRageshake}>Send Debug Logs</Button>
|
<Button onPress={submitRageshake}>
|
||||||
|
{sent
|
||||||
|
? "Debug Logs Sent"
|
||||||
|
: sending
|
||||||
|
? "Sending Debug Logs..."
|
||||||
|
: "Send Debug Logs"}
|
||||||
|
</Button>
|
||||||
</FieldRow>
|
</FieldRow>
|
||||||
|
{error && (
|
||||||
|
<FieldRow>
|
||||||
|
<ErrorMessage>{error.message}</ErrorMessage>
|
||||||
|
</FieldRow>
|
||||||
|
)}
|
||||||
<FieldRow>
|
<FieldRow>
|
||||||
<Button onPress={downloadDebugLog}>Download Debug Logs</Button>
|
<Button onPress={downloadDebugLog}>Download Debug Logs</Button>
|
||||||
</FieldRow>
|
</FieldRow>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useCallback, useContext } from "react";
|
import { useCallback, useContext, useState } from "react";
|
||||||
import * as rageshake from "matrix-react-sdk/src/rageshake/rageshake";
|
import * as rageshake from "matrix-react-sdk/src/rageshake/rageshake";
|
||||||
import pako from "pako";
|
import pako from "pako";
|
||||||
import { useClient } from "../ClientContext";
|
import { useClient } from "../ClientContext";
|
||||||
|
|
@ -6,186 +6,205 @@ import { InspectorContext } from "../room/GroupCallInspector";
|
||||||
|
|
||||||
export function useSubmitRageshake() {
|
export function useSubmitRageshake() {
|
||||||
const { client } = useClient();
|
const { client } = useClient();
|
||||||
const [{ json, svg }] = useContext(InspectorContext);
|
const [{ json }] = useContext(InspectorContext);
|
||||||
|
|
||||||
|
const [{ sending, sent, error }, setState] = useState({
|
||||||
|
sending: false,
|
||||||
|
sent: false,
|
||||||
|
error: null,
|
||||||
|
});
|
||||||
|
|
||||||
const submitRageshake = useCallback(
|
const submitRageshake = useCallback(
|
||||||
async (opts) => {
|
async (opts) => {
|
||||||
let userAgent = "UNKNOWN";
|
if (sending) {
|
||||||
if (window.navigator && window.navigator.userAgent) {
|
return;
|
||||||
userAgent = window.navigator.userAgent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let touchInput = "UNKNOWN";
|
|
||||||
try {
|
try {
|
||||||
// MDN claims broad support across browsers
|
setState({ sending: true, sent: false, error: null });
|
||||||
touchInput = String(window.matchMedia("(pointer: coarse)").matches);
|
|
||||||
} catch (e) {}
|
|
||||||
|
|
||||||
const body = new FormData();
|
let userAgent = "UNKNOWN";
|
||||||
body.append(
|
if (window.navigator && window.navigator.userAgent) {
|
||||||
"text",
|
userAgent = window.navigator.userAgent;
|
||||||
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) {
|
let touchInput = "UNKNOWN";
|
||||||
body.append("label", opts.label);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add storage persistence/quota information
|
|
||||||
if (navigator.storage && navigator.storage.persisted) {
|
|
||||||
try {
|
try {
|
||||||
body.append(
|
// MDN claims broad support across browsers
|
||||||
"storageManager_persisted",
|
touchInput = String(window.matchMedia("(pointer: coarse)").matches);
|
||||||
String(await navigator.storage.persisted())
|
|
||||||
);
|
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
} else if (document.hasStorageAccess) {
|
|
||||||
// Safari
|
|
||||||
try {
|
|
||||||
body.append(
|
|
||||||
"storageManager_persisted",
|
|
||||||
String(await document.hasStorageAccess())
|
|
||||||
);
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (navigator.storage && navigator.storage.estimate) {
|
const body = new FormData();
|
||||||
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) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
body.append(
|
||||||
"file",
|
"text",
|
||||||
new Blob([JSON.stringify(json)], { type: "text/plain" }),
|
opts.description || "User did not supply any additional text."
|
||||||
"groupcall.txt"
|
|
||||||
);
|
);
|
||||||
}
|
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);
|
||||||
|
|
||||||
await fetch(
|
if (client) {
|
||||||
import.meta.env.VITE_RAGESHAKE_SUBMIT_URL ||
|
body.append("user_id", client.credentials.userId);
|
||||||
"https://element.io/bugreports/submit",
|
body.append("device_id", client.deviceId);
|
||||||
{
|
|
||||||
method: "POST",
|
if (client.isCryptoEnabled()) {
|
||||||
body,
|
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) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.txt"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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]
|
[client]
|
||||||
);
|
);
|
||||||
|
|
@ -205,5 +224,5 @@ export function useSubmitRageshake() {
|
||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
return { submitRageshake, downloadDebugLog };
|
return { submitRageshake, sending, sent, error, downloadDebugLog };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue