mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-08-28 17:21:05 +00:00
fix: harden extension security and plugin reliability
Address audit findings across background handlers, openers, plugins, and UI: URL allowlists, XSS reductions, popup lifecycle fixes, plugin dispose/cleanup, cloud sync hardening, global search mathjs sandbox, and settings storage fixes.
This commit is contained in:
@@ -268,7 +268,7 @@
|
||||
|
||||
xScale={scaleBand().padding(distribution().modeUsed === "letter" ? 0.22 : 0.28)}
|
||||
|
||||
yScale={yScale()}
|
||||
yScale={yScale}
|
||||
|
||||
x="grade"
|
||||
|
||||
|
||||
@@ -35,6 +35,15 @@
|
||||
),
|
||||
);
|
||||
|
||||
$effect(() => {
|
||||
sortedData.length;
|
||||
itemsPerPage;
|
||||
const maxPage = Math.max(0, pageCount - 1);
|
||||
if (currentPage > maxPage) {
|
||||
currentPage = maxPage;
|
||||
}
|
||||
});
|
||||
|
||||
function toggleSort(column: keyof Assessment) {
|
||||
if (sortColumn === column) {
|
||||
sortDirection = sortDirection === "asc" ? "desc" : "asc";
|
||||
|
||||
@@ -53,8 +53,9 @@
|
||||
const [minG, maxG] = gradeRange;
|
||||
return analyticsData.filter((a) => {
|
||||
if (filterSubjects.length && !filterSubjects.includes(a.subject)) return false;
|
||||
const grade = a.finalGrade ?? -1;
|
||||
if (grade < minG || grade > maxG) return false;
|
||||
if (a.finalGrade !== undefined) {
|
||||
if (a.finalGrade < minG || a.finalGrade > maxG) return false;
|
||||
}
|
||||
if (
|
||||
filterSearch &&
|
||||
!a.title.toLowerCase().includes(filterSearch.toLowerCase()) &&
|
||||
|
||||
@@ -24,6 +24,9 @@ async function fetchJSON(url: string, body: Record<string, unknown>) {
|
||||
headers: { "Content-Type": "application/json; charset=utf-8" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP ${res.status} for ${url}`);
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
||||
@@ -254,10 +257,19 @@ async function loadAllPast(
|
||||
const results: Record<string, unknown>[][] = [];
|
||||
for (let i = 0; i < subjects.length; i += PAST_FETCH_CONCURRENCY) {
|
||||
const batch = subjects.slice(i, i + PAST_FETCH_CONCURRENCY);
|
||||
const batchResults = await Promise.all(
|
||||
const batchResults = await Promise.allSettled(
|
||||
batch.map((s) => loadPastForSubject(studentId, s)),
|
||||
);
|
||||
results.push(...batchResults);
|
||||
for (const result of batchResults) {
|
||||
if (result.status === "fulfilled") {
|
||||
results.push(result.value);
|
||||
} else {
|
||||
console.error(
|
||||
"[BetterSEQTA+] Past assessments fetch failed:",
|
||||
result.reason,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results.flat();
|
||||
}
|
||||
@@ -295,7 +307,7 @@ function mergeRawAssessments(
|
||||
}
|
||||
|
||||
export async function getStudentId(): Promise<number> {
|
||||
const info = await getUserInfo();
|
||||
const info = await getUserInfo({ validateSession: true });
|
||||
const id = Number(info?.id);
|
||||
if (!id || isNaN(id)) throw new Error("Could not resolve student ID");
|
||||
return id;
|
||||
|
||||
Reference in New Issue
Block a user