1
- import type { WebNavigation } from 'webextension-polyfill' ;
2
- import { runtime , scripting , tabs , webNavigation } from 'webextension-polyfill' ;
1
+ import { runtime , scripting , storage , tabs , webNavigation } from 'webextension-polyfill' ;
3
2
import { fetchUser } from './gkApi' ;
4
3
import { injectionScope as inject_azureDevops } from './hosts/azureDevops' ;
5
4
import { injectionScope as inject_bitbucket } from './hosts/bitbucket' ;
6
5
import { injectionScope as inject_github } from './hosts/github' ;
7
6
import { injectionScope as inject_gitlab } from './hosts/gitlab' ;
8
- import { refreshPermissions } from './permissions-helper' ;
7
+ import { domainToMatchPattern , refreshPermissions } from './permissions-helper' ;
9
8
import { getEnterpriseConnections , GKDotDevUrl , PermissionsGrantedMessage , PopupInitMessage } from './shared' ;
10
9
import type { CacheContext } from './types' ;
11
10
@@ -23,6 +22,19 @@ const DefaultInjectionDomains: InjectionDomains = {
23
22
azureDevops : [ 'dev.azure.com' ] ,
24
23
} ;
25
24
25
+ webNavigation . onDOMContentLoaded . addListener ( async details => {
26
+ const injectionDomains = await getInjectionDomains ( ) ;
27
+
28
+ const injectionFn = getInjectionFn ( details . url , injectionDomains ) ;
29
+ if ( injectionFn ) {
30
+ void scripting . executeScript ( {
31
+ target : { tabId : details . tabId } ,
32
+ func : injectionFn ,
33
+ args : [ details . url , GKDotDevUrl ] ,
34
+ } ) ;
35
+ }
36
+ } ) ;
37
+
26
38
webNavigation . onHistoryStateUpdated . addListener ( details => {
27
39
// used to detect when the user navigates to a different page in the same tab
28
40
const url = new URL ( details . url ) ;
@@ -39,14 +51,55 @@ runtime.onMessage.addListener(async msg => {
39
51
const context : CacheContext = { } ;
40
52
return refreshPermissions ( context ) ;
41
53
} else if ( msg === PermissionsGrantedMessage ) {
42
- // Reload extension to update injection listener
43
- runtime . reload ( ) ;
54
+ await storage . session . remove ( 'injectionDomains' ) ;
44
55
return undefined ;
45
56
}
46
57
console . error ( 'Recevied unknown runtime message' , msg ) ;
47
58
return undefined ;
48
59
} ) ;
49
60
61
+ runtime . onInstalled . addListener ( injectIntoCurrentTabs ) ;
62
+ runtime . onStartup . addListener ( injectIntoCurrentTabs ) ;
63
+
64
+ async function injectIntoCurrentTabs ( ) {
65
+ const injectionDomains = await getInjectionDomains ( ) ;
66
+ const allDomains = Object . values < string [ ] > ( injectionDomains as any ) . flat ( ) ;
67
+
68
+ const currentTabs = await tabs . query ( {
69
+ url : allDomains . map ( domainToMatchPattern ) ,
70
+ status : 'complete' ,
71
+ discarded : false ,
72
+ } ) ;
73
+ currentTabs . forEach ( tab => {
74
+ if ( tab . id && tab . url ) {
75
+ const injectionFn = getInjectionFn ( tab . url , injectionDomains ) ;
76
+ if ( injectionFn ) {
77
+ void scripting . executeScript ( {
78
+ target : { tabId : tab . id } ,
79
+ func : injectionFn ,
80
+ args : [ tab . url , GKDotDevUrl ] ,
81
+ } ) ;
82
+ }
83
+ }
84
+ } ) ;
85
+ }
86
+
87
+ async function getInjectionDomains ( ) {
88
+ let { injectionDomains } = ( await storage . session . get ( 'injectionDomains' ) ) as {
89
+ injectionDomains ?: InjectionDomains ;
90
+ } ;
91
+ if ( ! injectionDomains ) {
92
+ const context : CacheContext = { } ;
93
+ // This removes unneded permissions
94
+ await refreshPermissions ( context ) ;
95
+
96
+ injectionDomains = await computeInjectionDomains ( context ) ;
97
+ await storage . session . set ( { injectionDomains : injectionDomains } ) ;
98
+ }
99
+
100
+ return injectionDomains ;
101
+ }
102
+
50
103
async function computeInjectionDomains ( context : CacheContext ) {
51
104
const injectionDomains = structuredClone ( DefaultInjectionDomains ) ;
52
105
const enterpriseConnections = await getEnterpriseConnections ( context ) ;
@@ -63,33 +116,14 @@ async function computeInjectionDomains(context: CacheContext) {
63
116
return injectionDomains ;
64
117
}
65
118
66
- async function addInjectionListener ( context : CacheContext ) {
67
- const injectionDomains = await computeInjectionDomains ( context ) ;
68
- const allDomains = Object . values < string [ ] > ( injectionDomains as any ) . flat ( ) ;
69
-
70
- // note: This is a closure over injectionDomains
71
- const injectScript = ( details : WebNavigation . OnDOMContentLoadedDetailsType ) => {
72
- void scripting . executeScript ( {
73
- target : { tabId : details . tabId } ,
74
- // injectImmediately: true,
75
- func : getInjectionFn ( details . url , injectionDomains ) ,
76
- args : [ details . url , GKDotDevUrl ] ,
77
- } ) ;
78
- } ;
79
-
80
- webNavigation . onDOMContentLoaded . addListener ( injectScript , {
81
- url : allDomains . map ( domain => ( { hostContains : domain } ) ) ,
82
- } ) ;
83
- }
84
-
85
119
function urlHostHasDomain ( url : URL , domains : string [ ] ) : boolean {
86
120
return domains . some ( domain => url . hostname . endsWith ( domain ) ) ;
87
121
}
88
122
89
123
function getInjectionFn (
90
124
rawUrl : string ,
91
125
injectionDomains : InjectionDomains ,
92
- ) : ( url : string , gkDotDevUrl : string ) => void {
126
+ ) : ( ( url : string , gkDotDevUrl : string ) => void ) | null {
93
127
const url = new URL ( rawUrl ) ;
94
128
if ( urlHostHasDomain ( url , injectionDomains . github ) ) {
95
129
return inject_github ;
@@ -107,20 +141,12 @@ function getInjectionFn(
107
141
return inject_azureDevops ;
108
142
}
109
143
110
- console . error ( 'Unsupported host' ) ;
111
- throw new Error ( 'Unsupported host' ) ;
144
+ return null ;
112
145
}
113
146
114
147
async function main ( ) {
115
148
// The fetchUser function also updates the extension icon if the user is logged in
116
149
await fetchUser ( ) ;
117
-
118
- const context : CacheContext = { } ;
119
- // This removes unneded permissions
120
- await refreshPermissions ( context ) ;
121
- // NOTE: This may request hosts that we may not have permissions for, which will log errors for the extension
122
- // This does not cause any issues, and eliminating the errors requires more logic
123
- await addInjectionListener ( context ) ;
124
150
}
125
151
126
152
void main ( ) ;
0 commit comments