mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-05 19:24:39 +00:00
fix: fix qr code to use safer methoed & bump ver
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "betterseqtaplus",
|
"name": "betterseqtaplus",
|
||||||
"version": "3.5.0",
|
"version": "3.5.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Enhance SEQTA Learn's usability and aesthetics! A fork of BetterSEQTA to continue development add add heaps more features!",
|
"description": "Enhance SEQTA Learn's usability and aesthetics! A fork of BetterSEQTA to continue development add add heaps more features!",
|
||||||
"browserslist": "> 0.5%, last 2 versions, not dead",
|
"browserslist": "> 0.5%, last 2 versions, not dead",
|
||||||
|
|||||||
@@ -11,6 +11,30 @@ import { main } from "@/seqta/main";
|
|||||||
import { delay } from "./seqta/utils/delay";
|
import { delay } from "./seqta/utils/delay";
|
||||||
import { initializeHideSensitiveToggle } from "@/seqta/utils/hideSensitiveToggle";
|
import { initializeHideSensitiveToggle } from "@/seqta/utils/hideSensitiveToggle";
|
||||||
|
|
||||||
|
function registerFetchSeqtaAppLinkListener() {
|
||||||
|
browser.runtime.onMessage.addListener((request, _sender, sendResponse) => {
|
||||||
|
if (request?.type !== "fetchSeqtaAppLink") return false;
|
||||||
|
void (async () => {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${location.origin}/seqta/student/load/profile`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
credentials: "include",
|
||||||
|
body: JSON.stringify({}),
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
const statusOk = data?.status === "200" || data?.status === 200;
|
||||||
|
const raw = data?.payload?.app_link;
|
||||||
|
const appLink = typeof raw === "string" && raw.length > 0 ? raw : null;
|
||||||
|
sendResponse({ appLink: statusOk ? appLink : null });
|
||||||
|
} catch {
|
||||||
|
sendResponse({ appLink: null });
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export let MenuOptionsOpen = false;
|
export let MenuOptionsOpen = false;
|
||||||
|
|
||||||
var IsSEQTAPage = false;
|
var IsSEQTAPage = false;
|
||||||
@@ -30,6 +54,8 @@ async function init() {
|
|||||||
IsSEQTAPage = true;
|
IsSEQTAPage = true;
|
||||||
console.info("[BetterSEQTA+] Verified SEQTA Page");
|
console.info("[BetterSEQTA+] Verified SEQTA Page");
|
||||||
|
|
||||||
|
registerFetchSeqtaAppLinkListener();
|
||||||
|
|
||||||
const documentLoadStyle = document.createElement("style");
|
const documentLoadStyle = document.createElement("style");
|
||||||
documentLoadStyle.textContent = documentLoadCSS;
|
documentLoadStyle.textContent = documentLoadCSS;
|
||||||
document.head.appendChild(documentLoadStyle);
|
document.head.appendChild(documentLoadStyle);
|
||||||
|
|||||||
+38
-18
@@ -167,8 +167,19 @@ function handleCloudFavorite(request: any, sendResponse: MessageSender): boolean
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Handler for a message type; receives request and sendResponse callback */
|
/** Handler for a message type; receives request, sendResponse, and optional sender (for tab routing) */
|
||||||
type MessageHandler = { (request: any, sendResponse: MessageSender): boolean | void };
|
type MessageHandler = {
|
||||||
|
(request: any, sendResponse: MessageSender, sender?: browser.Runtime.MessageSender): boolean | void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function isSeqtaOrigin(origin: string): boolean {
|
||||||
|
try {
|
||||||
|
const u = new URL(origin);
|
||||||
|
return u.hostname.includes("seqta") || u.hostname.endsWith(".edu.au");
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const MESSAGE_HANDLERS: Record<string, MessageHandler> = {
|
const MESSAGE_HANDLERS: Record<string, MessageHandler> = {
|
||||||
reloadTabs: () => reloadSeqtaPages(),
|
reloadTabs: () => reloadSeqtaPages(),
|
||||||
@@ -200,29 +211,38 @@ const MESSAGE_HANDLERS: Record<string, MessageHandler> = {
|
|||||||
cloudLogin: handleCloudLogin,
|
cloudLogin: handleCloudLogin,
|
||||||
cloudRefresh: handleCloudRefresh,
|
cloudRefresh: handleCloudRefresh,
|
||||||
cloudFavorite: handleCloudFavorite,
|
cloudFavorite: handleCloudFavorite,
|
||||||
getSeqtaSession: (req: { baseUrl?: string }, sendResponse: MessageSender) => {
|
getSeqtaSession: (req: { baseUrl?: string }, sendResponse: MessageSender, sender?: browser.Runtime.MessageSender) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
let baseUrl = req.baseUrl;
|
let tabId = sender?.tab?.id;
|
||||||
if (!baseUrl) {
|
let originForCheck: string | undefined = req.baseUrl;
|
||||||
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
|
|
||||||
|
if (tabId == null) {
|
||||||
|
const tabs = await browser.tabs.query({ active: true, lastFocusedWindow: true });
|
||||||
const tab = tabs[0];
|
const tab = tabs[0];
|
||||||
if (!tab?.url) {
|
if (!tab?.id || !tab.url) {
|
||||||
sendResponse({ session: null });
|
sendResponse({ appLink: null });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
baseUrl = new URL(tab.url).origin;
|
tabId = tab.id;
|
||||||
|
if (!originForCheck) originForCheck = new URL(tab.url).origin;
|
||||||
|
} else if (!originForCheck && sender?.tab?.url) {
|
||||||
|
originForCheck = new URL(sender.tab.url).origin;
|
||||||
}
|
}
|
||||||
const cookies = await browser.cookies.getAll({ url: baseUrl });
|
|
||||||
const jsession = cookies.find((c) => c.name === "JSESSIONID");
|
if (!originForCheck || !isSeqtaOrigin(originForCheck)) {
|
||||||
if (jsession?.value) {
|
sendResponse({ appLink: null });
|
||||||
sendResponse({ session: { baseUrl, jsessionId: jsession.value } });
|
return;
|
||||||
} else {
|
|
||||||
sendResponse({ session: null });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const reply = (await browser.tabs.sendMessage(tabId, { type: "fetchSeqtaAppLink" })) as
|
||||||
|
| { appLink?: string | null }
|
||||||
|
| undefined;
|
||||||
|
const appLink = typeof reply?.appLink === "string" && reply.appLink.length > 0 ? reply.appLink : null;
|
||||||
|
sendResponse({ appLink });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("[Background] getSeqtaSession error:", err);
|
console.error("[Background] getSeqtaSession error:", err);
|
||||||
sendResponse({ session: null });
|
sendResponse({ appLink: null });
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
return true;
|
return true;
|
||||||
@@ -231,10 +251,10 @@ const MESSAGE_HANDLERS: Record<string, MessageHandler> = {
|
|||||||
|
|
||||||
browser.runtime.onMessage.addListener(
|
browser.runtime.onMessage.addListener(
|
||||||
// @ts-ignore - OnMessageListener expects literal true for async, we return boolean
|
// @ts-ignore - OnMessageListener expects literal true for async, we return boolean
|
||||||
(request: any, _: any, sendResponse: MessageSender) => {
|
(request: any, sender: browser.Runtime.MessageSender, sendResponse: MessageSender) => {
|
||||||
const handler = MESSAGE_HANDLERS[request.type];
|
const handler = MESSAGE_HANDLERS[request.type];
|
||||||
if (handler) {
|
if (handler) {
|
||||||
const result = handler(request, sendResponse);
|
const result = handler(request, sendResponse, sender);
|
||||||
return result === true;
|
return result === true;
|
||||||
}
|
}
|
||||||
console.log("Unknown request type");
|
console.log("Unknown request type");
|
||||||
|
|||||||
@@ -4,11 +4,9 @@
|
|||||||
import QRCode from "qrcode";
|
import QRCode from "qrcode";
|
||||||
import { portal } from "../utils/portal";
|
import { portal } from "../utils/portal";
|
||||||
|
|
||||||
const DEEPLINK_PREFIX = "desqta://connect/";
|
|
||||||
|
|
||||||
let showQrModal = $state(false);
|
let showQrModal = $state(false);
|
||||||
let qrDataUrl = $state<string | null>(null);
|
let qrDataUrl = $state<string | null>(null);
|
||||||
let deeplink = $state<string | null>(null);
|
let appLink = $state<string | null>(null);
|
||||||
let errorMessage = $state<string | null>(null);
|
let errorMessage = $state<string | null>(null);
|
||||||
let isLoading = $state(false);
|
let isLoading = $state(false);
|
||||||
let isStandalone = $state(false);
|
let isStandalone = $state(false);
|
||||||
@@ -38,30 +36,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildDesqtaConnectPayload(baseUrl: string, jsessionId: string): string {
|
async function getAppLink(): Promise<string | null> {
|
||||||
const payload = JSON.stringify({ u: baseUrl, s: jsessionId });
|
|
||||||
const base64 = btoa(unescape(encodeURIComponent(payload)));
|
|
||||||
const encoded = encodeURIComponent(base64);
|
|
||||||
return `${DEEPLINK_PREFIX}${encoded}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getSession(): Promise<{ baseUrl: string; jsessionId: string } | null> {
|
|
||||||
let baseUrl: string | undefined;
|
let baseUrl: string | undefined;
|
||||||
|
|
||||||
if (isExtensionPage()) {
|
if (isExtensionPage()) {
|
||||||
// Extension popup: background will get URL from active tab
|
|
||||||
baseUrl = undefined;
|
baseUrl = undefined;
|
||||||
} else {
|
} else {
|
||||||
// In-page (settings inside SEQTA): pass current page URL (cookies API not available in content scripts)
|
|
||||||
baseUrl = normalizeBaseUrl(window.location.href);
|
baseUrl = normalizeBaseUrl(window.location.href);
|
||||||
if (!isSeqtaUrl(baseUrl)) return null;
|
if (!isSeqtaUrl(baseUrl)) return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { session } = (await browser.runtime.sendMessage({
|
const { appLink: link } = (await browser.runtime.sendMessage({
|
||||||
type: "getSeqtaSession",
|
type: "getSeqtaSession",
|
||||||
baseUrl,
|
baseUrl,
|
||||||
})) as { session: { baseUrl: string; jsessionId: string } | null };
|
})) as { appLink: string | null };
|
||||||
return session ?? null;
|
return link ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateQrCode() {
|
async function generateQrCode() {
|
||||||
@@ -71,9 +60,9 @@
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
isStandalone = isExtensionPage();
|
isStandalone = isExtensionPage();
|
||||||
const session = await getSession();
|
const link = await getAppLink();
|
||||||
|
|
||||||
if (!session) {
|
if (!link) {
|
||||||
if (isStandalone) {
|
if (isStandalone) {
|
||||||
errorMessage =
|
errorMessage =
|
||||||
"Open SEQTA Learn in a tab and log in, then open settings from that tab to generate a QR code.";
|
"Open SEQTA Learn in a tab and log in, then open settings from that tab to generate a QR code.";
|
||||||
@@ -83,9 +72,8 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const link = buildDesqtaConnectPayload(session.baseUrl, session.jsessionId);
|
|
||||||
const dataUrl = await QRCode.toDataURL(link, { width: 256, margin: 2 });
|
const dataUrl = await QRCode.toDataURL(link, { width: 256, margin: 2 });
|
||||||
deeplink = link;
|
appLink = link;
|
||||||
qrDataUrl = dataUrl;
|
qrDataUrl = dataUrl;
|
||||||
showQrModal = true;
|
showQrModal = true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -99,12 +87,12 @@
|
|||||||
function closeModal() {
|
function closeModal() {
|
||||||
showQrModal = false;
|
showQrModal = false;
|
||||||
qrDataUrl = null;
|
qrDataUrl = null;
|
||||||
deeplink = null;
|
appLink = null;
|
||||||
errorMessage = null;
|
errorMessage = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function openInDesqta() {
|
function openAppLink() {
|
||||||
if (deeplink) window.location.href = deeplink;
|
if (appLink) window.location.href = appLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadQrImage() {
|
function downloadQrImage() {
|
||||||
@@ -160,12 +148,12 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-center p-4 bg-white rounded-xl dark:bg-zinc-900">
|
<div class="flex justify-center p-4 bg-white rounded-xl dark:bg-zinc-900">
|
||||||
<img src={qrDataUrl} alt="DesQTA QR Code" class="w-64 h-64" />
|
<img src={qrDataUrl} alt="SEQTA Learn app link QR code" class="w-64 h-64" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2 mt-4">
|
<div class="flex flex-col gap-2 mt-4">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onclick={openInDesqta}
|
onclick={openAppLink}
|
||||||
class="px-4 py-2.5 w-full text-sm font-medium text-white bg-indigo-600 rounded-lg transition-colors dark:bg-indigo-500 hover:bg-indigo-700 dark:hover:bg-indigo-600">
|
class="px-4 py-2.5 w-full text-sm font-medium text-white bg-indigo-600 rounded-lg transition-colors dark:bg-indigo-500 hover:bg-indigo-700 dark:hover:bg-indigo-600">
|
||||||
Sign into DesQTA Desktop
|
Sign into DesQTA Desktop
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
"64": "resources/icons/icon-64.png"
|
"64": "resources/icons/icon-64.png"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"permissions": ["tabs", "notifications", "storage", "cookies"],
|
"permissions": ["tabs", "notifications", "storage"],
|
||||||
"host_permissions": ["https://newsapi.org/", "https://betterseqta.org/", "https://accounts.betterseqta.org/", "*://*/*"],
|
"host_permissions": ["https://newsapi.org/", "https://betterseqta.org/", "https://accounts.betterseqta.org/", "*://*/*"],
|
||||||
"background": {
|
"background": {
|
||||||
"service_worker": "background.ts"
|
"service_worker": "background.ts"
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ export function OpenWhatsNewPopup() {
|
|||||||
const text = stringToHTML(/* html */ `
|
const text = stringToHTML(/* html */ `
|
||||||
<div class="whatsnewTextContainer" style="height: 50%;overflow-y: auto;">
|
<div class="whatsnewTextContainer" style="height: 50%;overflow-y: auto;">
|
||||||
|
|
||||||
|
<h1>3.5.1 - QR & session link fix</h1>
|
||||||
|
<li>Fixed DesQTA Connect Mobile App QR generation on Chrome</li>
|
||||||
|
|
||||||
<h1>3.5.0 - Adaptive Theme, Timetable Editor & More</h1>
|
<h1>3.5.0 - Adaptive Theme, Timetable Editor & More</h1>
|
||||||
<li>Added adaptive theme colour</li>
|
<li>Added adaptive theme colour</li>
|
||||||
<li>Added optional soft gradient for adaptive theme when viewing a class</li>
|
<li>Added optional soft gradient for adaptive theme when viewing a class</li>
|
||||||
|
|||||||
Reference in New Issue
Block a user