-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: script injection via browser extension
- Loading branch information
1 parent
5c2ed08
commit bd39c21
Showing
21 changed files
with
265 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"$schema": "https://turbo.build/schema.json", | ||
"extends": ["//"], | ||
"tasks": { | ||
"start": { | ||
"dependsOn": ["^build"] | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { Message } from './message'; | ||
import { MessageData } from './message-data'; | ||
|
||
type SubscriptionCallback<T = unknown> = (payload: T) => void; | ||
type MessageEventListener = (event: MessageEvent) => void; | ||
|
||
export class MessageBus { | ||
#channel: BroadcastChannel = new BroadcastChannel('__consy-message-bus'); | ||
|
||
#eventListenerBySubscriptionCallback: Map<SubscriptionCallback<MessageData>, MessageEventListener> = new Map< | ||
SubscriptionCallback<MessageData>, | ||
MessageEventListener | ||
>(); | ||
|
||
public publish(message: MessageData): void { | ||
console.log('Publishing message', message); | ||
|
||
this.#channel.postMessage(message); | ||
} | ||
|
||
public subscribe(callback: SubscriptionCallback<MessageData>): void { | ||
if (this.#eventListenerBySubscriptionCallback.has(callback)) { | ||
return; | ||
} | ||
|
||
const messageEventListener: MessageEventListener = (event: MessageEvent) => { | ||
const payload: unknown = event.data; | ||
if (!Message.isAbstractMessageData(payload)) { | ||
throw new Error(`Received event doesn't contain a compatible message data object`); | ||
} | ||
callback(payload); | ||
}; | ||
this.#channel.addEventListener('message', messageEventListener); | ||
this.#eventListenerBySubscriptionCallback.set(callback, messageEventListener); | ||
} | ||
|
||
public unsubscribe(callback: SubscriptionCallback<MessageData>): void { | ||
const messageEventListener: MessageEventListener | undefined = | ||
this.#eventListenerBySubscriptionCallback.get(callback); | ||
if (messageEventListener === undefined) { | ||
return; | ||
} | ||
|
||
this.#channel.removeEventListener('message', messageEventListener); | ||
this.#eventListenerBySubscriptionCallback.delete(callback); | ||
} | ||
|
||
public close(): void { | ||
this.#eventListenerBySubscriptionCallback.forEach( | ||
(_listener: MessageEventListener, callback: SubscriptionCallback<MessageData>) => { | ||
this.unsubscribe(callback); | ||
} | ||
); | ||
|
||
this.#channel.close(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export interface MessageData<P extends {} = {}> { | ||
readonly type: Lowercase<string>; | ||
readonly payload: P; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { MessageData } from './message-data'; | ||
|
||
export abstract class Message<P extends {}> implements MessageData<P> { | ||
abstract readonly type: Lowercase<string>; | ||
|
||
constructor(public readonly payload: P) {} | ||
|
||
public static isAbstractMessageData(message: unknown): message is MessageData { | ||
return typeof message === 'object' && message !== null && 'type' in message; | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
extension/src/communication/messages/mounted-instances.message.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Message } from '../message'; | ||
|
||
interface MountedInstance { | ||
key: string; | ||
} | ||
|
||
export class MountedInstancesMessage extends Message<MountedInstance[]> { | ||
public static readonly type: 'mounted-instances' = 'mounted-instances'; | ||
public readonly type: typeof MountedInstancesMessage.type = MountedInstancesMessage.type; | ||
|
||
public static isMessageData( | ||
message: unknown | ||
): message is Pick<InstanceType<typeof MountedInstancesMessage>, 'type' | 'payload'> { | ||
return Message.isAbstractMessageData(message) && message.type === MountedInstancesMessage.type; | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
extension/src/communication/messages/not-mounted.message.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Message } from '../message'; | ||
|
||
export class NotMountedMessage extends Message<{}> { | ||
public static readonly type: 'not-mounted' = 'not-mounted'; | ||
public readonly type: typeof NotMountedMessage.type = NotMountedMessage.type; | ||
|
||
constructor() { | ||
super({}); | ||
} | ||
|
||
public static isMessageData( | ||
message: unknown | ||
): message is Pick<InstanceType<typeof NotMountedMessage>, 'type' | 'payload'> { | ||
return Message.isAbstractMessageData(message) && message.type === NotMountedMessage.type; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Acessor, EXPOSED_KEYS_PROPERTY_NAME } from '@consy/declarations'; | ||
import { MessageBus } from './communication/message-bus'; | ||
import { MountedInstancesMessage } from './communication/messages/mounted-instances.message'; | ||
import { NotMountedMessage } from './communication/messages/not-mounted.message'; | ||
|
||
const messageBus: MessageBus = new MessageBus(); | ||
|
||
(() => { | ||
const exposedKeysAccessor: Acessor<string[], string> = new Acessor<string[], string>(window); | ||
if (!exposedKeysAccessor.isMounted(EXPOSED_KEYS_PROPERTY_NAME)) { | ||
messageBus.publish(new NotMountedMessage()); | ||
return; | ||
} | ||
const exposedKeys: string[] = exposedKeysAccessor.getValue(EXPOSED_KEYS_PROPERTY_NAME); | ||
messageBus.publish(new MountedInstancesMessage(exposedKeys.map((key: string) => ({ key })))); | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,23 @@ | ||
console.log('This is a popup!'); | ||
import { MessageBus } from './communication/message-bus'; | ||
import { MountedInstancesMessage } from './communication/messages/mounted-instances.message'; | ||
import { NotMountedMessage } from './communication/messages/not-mounted.message'; | ||
|
||
const messageBus: MessageBus = new MessageBus(); | ||
|
||
messageBus.subscribe((messageData: unknown) => { | ||
switch (true) { | ||
case NotMountedMessage.isMessageData(messageData): { | ||
console.log('Not mounted'); | ||
return; | ||
} | ||
|
||
case MountedInstancesMessage.isMessageData(messageData): { | ||
console.log(messageData.payload); | ||
return; | ||
} | ||
|
||
default: { | ||
return; | ||
} | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,54 @@ | ||
import { PromiseRejector } from '@consy/declarations'; | ||
|
||
function getActiveTab(): Promise<chrome.tabs.Tab> { | ||
return new Promise((resolve: PromiseRejector<chrome.tabs.Tab>, reject: PromiseRejector<Error>) => { | ||
chrome.tabs.query({ active: true, currentWindow: true }, (tabs: chrome.tabs.Tab[]) => { | ||
const firstActiveTab: chrome.tabs.Tab | undefined = tabs[0]; | ||
if (firstActiveTab === undefined) { | ||
return reject(new Error('No active tab found')); | ||
} | ||
import { MessageBus } from './communication/message-bus'; | ||
import { MountedInstancesMessage } from './communication/messages/mounted-instances.message'; | ||
import { NotMountedMessage } from './communication/messages/not-mounted.message'; | ||
|
||
resolve(firstActiveTab); | ||
}); | ||
}); | ||
} | ||
const messageBus: MessageBus = new MessageBus(); | ||
|
||
Promise.resolve() | ||
.then(async () => { | ||
const { id: tabId, url: activeTabUrl }: chrome.tabs.Tab = await getActiveTab(); | ||
messageBus.subscribe((messageData: unknown) => { | ||
switch (true) { | ||
case NotMountedMessage.isMessageData(messageData): { | ||
console.log('Not mounted'); | ||
return; | ||
} | ||
|
||
if (activeTabUrl === undefined || activeTabUrl.startsWith('chrome://')) { | ||
case MountedInstancesMessage.isMessageData(messageData): { | ||
console.log(messageData.payload); | ||
return; | ||
} | ||
|
||
if (tabId === undefined) { | ||
throw new Error('No active tab ID found'); | ||
default: { | ||
return; | ||
} | ||
} | ||
}); | ||
|
||
try { | ||
chrome.tabs.onUpdated.addListener( | ||
async ( | ||
tabId: number, | ||
changeInfo: { | ||
status?: chrome.tabs.TabStatus; | ||
}, | ||
tab: chrome.tabs.Tab | ||
) => { | ||
if (changeInfo.status !== 'complete' || tab.url === undefined) { | ||
return; | ||
} | ||
|
||
if (tabId === undefined) { | ||
throw new Error('No active tab ID found'); | ||
} | ||
|
||
await chrome.scripting.executeScript({ | ||
target: { tabId, allFrames: true }, | ||
func: () => { | ||
console.log('injected script'); | ||
const [injectionResult]: chrome.scripting.InjectionResult[] = await chrome.scripting.executeScript({ | ||
target: { tabId, allFrames: true }, | ||
files: ['injected-script.js'] | ||
}); | ||
|
||
if (injectionResult === undefined) { | ||
throw new Error('Script injection failed'); | ||
} | ||
}); | ||
console.log('script injected in all frames'); | ||
}) | ||
.catch((error: unknown) => { | ||
console.error(error instanceof Error ? error.message : 'Unknown error'); | ||
}); | ||
} | ||
); | ||
} catch (error: unknown) { | ||
console.error(error instanceof Error ? error.message : 'Unknown error'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
{ | ||
"$schema": "https://json.schemastore.org/tsconfig", | ||
"compilerOptions": { | ||
"outDir": "./tsc-out/scripts" | ||
}, | ||
"extends": "@consy/configs/typescript/node.json", | ||
"include": ["*.script.ts"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.