Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions src/background/handlers/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ export function handleMessage(
}

if (isGoBackActiveTabMessage(message)) {
void handleGoBackActiveTab(sendResponse);
void handleGoBackActiveTab(sender, sendResponse);
return true;
}

if (isContinueActiveTabMessage(message)) {
void handleContinueActiveTab(sendResponse);
void handleContinueActiveTab(message.blockId, sender, sendResponse);
return true;
}

Expand All @@ -67,12 +67,31 @@ async function handleCheckUrl(
sendResponse({ blocked: decision.action === 'block' });
}

async function handleGoBackActiveTab(sendResponse: (response: unknown) => void): Promise<void> {
sendResponse({ restored: await getTabController().goBackFromActiveTab() });
async function handleGoBackActiveTab(
sender: chrome.runtime.MessageSender,
sendResponse: (response: unknown) => void
): Promise<void> {
const senderTabId = sender.tab?.id;
const restored =
typeof senderTabId === 'number'
? await getTabController().goBackFromTab(senderTabId)
: await getTabController().goBackFromActiveTab();
sendResponse({ restored });
}

async function handleContinueActiveTab(sendResponse: (response: unknown) => void): Promise<void> {
sendResponse({ continued: await getTabController().continueFromActiveTab() });
async function handleContinueActiveTab(
blockId: string | undefined,
sender: chrome.runtime.MessageSender,
sendResponse: (response: unknown) => void
): Promise<void> {
const senderTabId = sender.tab?.id;
const continued =
typeof senderTabId === 'number'
? await getTabController().continueFromTab(senderTabId, sender.tab?.url, blockId)
: blockId
? await getTabController().continueFromBlockedPage(blockId)
: await getTabController().continueFromActiveTab();
sendResponse({ continued });
}

async function handleGetBlockedPageState(
Expand Down
46 changes: 36 additions & 10 deletions src/background/tabController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { getRulesProvider, type CurrentRules, type RulesProvider } from './rules
interface ResolvedBlockedTarget {
readonly targetUrl: string;
readonly blockId?: string;
readonly tabId?: number;
readonly hasSessionState: boolean;
}

Expand Down Expand Up @@ -196,7 +197,11 @@ class TabController {
return false;
}

const lastAllowedUrl = await getLastAllowedUrl(activeTab.id);
return this.goBackFromTab(activeTab.id);
}

async goBackFromTab(tabId: number): Promise<boolean> {
const lastAllowedUrl = await getLastAllowedUrl(tabId);
if (!lastAllowedUrl || isInternalUrl(lastAllowedUrl)) {
return false;
}
Expand All @@ -206,8 +211,8 @@ class TabController {
return false;
}

await updateTabUrl(activeTab.id, lastAllowedUrl);
await this.allowTab(activeTab.id, lastAllowedUrl);
await updateTabUrl(tabId, lastAllowedUrl);
await this.allowTab(tabId, lastAllowedUrl);
return true;
}

Expand All @@ -217,26 +222,44 @@ class TabController {
return false;
}

const resolvedTarget = await this.resolveBlockedTarget(activeTab.id, activeTab.url);
return this.continueFromTab(activeTab.id, activeTab.url);
}

async continueFromBlockedPage(blockId: string): Promise<boolean> {
const pageState = await getBlockedPageState(blockId);
if (!pageState) {
return false;
}

return this.continueFromTab(pageState.tabId, undefined, blockId);
}

async continueFromTab(
tabId: number,
blockedPageUrl?: string,
blockId?: string
): Promise<boolean> {
const resolvedTarget = await this.resolveBlockedTarget(tabId, blockedPageUrl, blockId);
if (!resolvedTarget) {
return false;
}

const targetTabId = resolvedTarget.tabId ?? tabId;
const rules = await this.getRules();
const decision = rules.engine.evaluate(resolvedTarget.targetUrl);
if (decision.action !== 'block' || decision.blockType !== 'warning') {
return false;
}

await Promise.all([
setWarningBypassState(activeTab.id, {
setWarningBypassState(targetTabId, {
filterId: decision.filterId,
urlKey: getWarningBypassUrlKey(resolvedTarget.targetUrl),
}),
clearBlockedTabState(activeTab.id),
setLastAllowedUrl(activeTab.id, resolvedTarget.targetUrl),
clearBlockedTabState(targetTabId),
setLastAllowedUrl(targetTabId, resolvedTarget.targetUrl),
]);
await updateTabUrl(activeTab.id, resolvedTarget.targetUrl);
await updateTabUrl(targetTabId, resolvedTarget.targetUrl);
return true;
}

Expand Down Expand Up @@ -353,16 +376,18 @@ class TabController {

private async resolveBlockedTarget(
tabId: number,
blockedPageUrl?: string
blockedPageUrl?: string,
explicitBlockId?: string
): Promise<ResolvedBlockedTarget | undefined> {
const existingState = await getBlockedTabState(tabId);
const blockId = parseBlockedPageBlockId(blockedPageUrl);
const blockId = explicitBlockId ?? parseBlockedPageBlockId(blockedPageUrl);
if (blockId) {
const pageState = await getBlockedPageState(blockId);
if (pageState) {
return {
targetUrl: pageState.targetUrl,
blockId,
tabId: pageState.tabId,
hasSessionState: true,
};
}
Expand All @@ -372,6 +397,7 @@ class TabController {
? {
targetUrl: existingState.targetUrl,
blockId: existingState.blockId,
tabId: existingState.tabId,
hasSessionState: true,
}
: undefined;
Expand Down
23 changes: 13 additions & 10 deletions src/blocked/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
* Displays information about the blocked URL and provides navigation options
*/

import { sendExtensionMessage } from '../shared/api';
import { openOptionsPage } from '../shared/api/runtime';
import {
MessageType,
type BlockedPageState,
type ContinueActiveTabResponse,
type FilterMatchMode,
type GetBlockedPageStateResponse,
type GoBackActiveTabResponse,
} from '../shared/types';
import { getElementByIdOrNull } from '../shared/utils/dom';
import { formatGroupScheduleSummary } from '../shared/utils/schedules';
Expand Down Expand Up @@ -66,10 +65,12 @@ async function renderPage(): Promise<void> {

async function getBlockedPageState(): Promise<BlockedPageViewModel> {
try {
const response = (await chrome.runtime.sendMessage({
type: MessageType.GET_BLOCKED_PAGE_STATE,
blockId: getBlockedPageBlockId(),
})) as GetBlockedPageStateResponse;
const blockId = getBlockedPageBlockId();
const response = await sendExtensionMessage(
blockId
? { type: MessageType.GET_BLOCKED_PAGE_STATE, blockId }
: { type: MessageType.GET_BLOCKED_PAGE_STATE }
);

if (!isBlockedPageStateResponse(response)) {
return getUnavailableBlockedPageState();
Expand Down Expand Up @@ -141,19 +142,21 @@ function isBlockedPageStateResponse(response: unknown): response is GetBlockedPa
}

async function handleGoBack(): Promise<void> {
const response = (await chrome.runtime.sendMessage({
const response = await sendExtensionMessage({
type: MessageType.GO_BACK_ACTIVE_TAB,
})) as GoBackActiveTabResponse;
});

if (!response.restored) {
console.warn('[Teichos] No restorable tab target is available.');
}
}

async function handleContinue(): Promise<void> {
const response = (await chrome.runtime.sendMessage({
const blockId = getBlockedPageBlockId();
const response = await sendExtensionMessage({
type: MessageType.CONTINUE_ACTIVE_TAB,
})) as ContinueActiveTabResponse;
...(blockId ? { blockId } : {}),
});

if (!response.continued) {
console.warn('[Teichos] No warning bypass is available for this tab.');
Expand Down
3 changes: 2 additions & 1 deletion src/options/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,13 @@ let setInfoPopoverOpen: ((isOpen: boolean) => void) | null = null;
* Initialize options page
*/
async function init(): Promise<void> {
await renderGroups();
setupEventListeners();
setupStorageSync();
populateInfoPanel();
await renderGroups();
openFilterFromQuery();
openInfoFromQuery();
document.documentElement.dataset['optionsReady'] = 'true';
}

/**
Expand Down
6 changes: 4 additions & 2 deletions src/popup/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
saveData,
setSnooze,
updateFilter,
sendExtensionMessage,
} from '../shared/api';
import { openOptionsPage, openOptionsPageWithParams } from '../shared/api/runtime';
import { getActiveTab } from '../shared/api/tabs';
Expand Down Expand Up @@ -96,10 +97,11 @@ async function disableExpiredTemporaryFilters(data: StorageData): Promise<Storag
* Initialize popup
*/
async function init(): Promise<void> {
await renderFilters();
setupEventListeners();
setupStorageSync();
ensureSnoozeCountdownTicker();
await renderFilters();
document.documentElement.dataset['popupReady'] = 'true';
}

/**
Expand All @@ -108,7 +110,7 @@ async function init(): Promise<void> {
function setupEventListeners(): void {
const openOptionsButton = getElementByIdOrNull('open-options');
openOptionsButton?.addEventListener('click', () => {
void chrome.runtime.sendMessage({ type: MessageType.CLOSE_INFO_PANEL });
void sendExtensionMessage({ type: MessageType.CLOSE_INFO_PANEL });
openOptionsPage()
.catch((error: unknown) => {
console.error('Failed to open options page:', error);
Expand Down
1 change: 1 addition & 0 deletions src/shared/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './storage';
export * from './runtime';
export * from './tabs';
export * from './session';
export * from './messaging';
7 changes: 7 additions & 0 deletions src/shared/api/messaging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { ExtensionMessage, MessageResponse } from '../types';

export async function sendExtensionMessage<T extends ExtensionMessage>(
message: T
): Promise<MessageResponse<T>> {
return (await chrome.runtime.sendMessage(message)) as MessageResponse<T>;
}
Loading
Loading