@@ -2,10 +2,20 @@ import { AppConstants } from 'resource://gre/modules/AppConstants.sys.mjs';
22import { NetUtil } from 'resource://gre/modules/NetUtil.sys.mjs' ;
33import { nsContentDispatchChooser } from 'resource://gre/modules/ContentDispatchChooser.sys.mjs' ;
44import { nsDefaultCommandLineHandler , nsBrowserContentHandler } from 'resource:///modules/BrowserContentHandler.sys.mjs' ;
5+ import { BrowserGlue } from 'resource:///modules/BrowserGlue.sys.mjs' ;
56import { BrowserWindowTracker } from 'resource:///modules/BrowserWindowTracker.sys.mjs' ;
7+ import { WebProtocolHandlerRegistrar } from 'resource:///modules/WebProtocolHandlerRegistrar.sys.mjs' ;
8+ import { OnboardingMessageProvider } from 'resource:///modules/asrouter/OnboardingMessageProvider.sys.mjs' ;
69
710import { applySystemIntegration } from 'resource://pwa/utils/systemIntegration.sys.mjs' ;
811
12+ const lazy = { } ;
13+
14+ ChromeUtils . defineESModuleGetters ( lazy , {
15+ sendNativeMessage : 'resource://pwa/utils/nativeMessaging.sys.mjs' ,
16+ sanitizeString : 'resource://pwa/utils/common.sys.mjs' ,
17+ } ) ;
18+
919/**
1020 * Reads the PWAsForFirefox config file and parses it as JSON.
1121 *
@@ -117,9 +127,18 @@ Services.prefs.getDefaultBranch(null).setBoolPref('browser.sessionstore.resume_f
117127Services . prefs . getDefaultBranch ( null ) . setIntPref ( 'browser.sessionstore.max_resumed_crashes' , 0 ) ;
118128Services . prefs . getDefaultBranch ( null ) . setIntPref ( 'browser.sessionstore.max_tabs_undo' , 0 ) ;
119129Services . prefs . getDefaultBranch ( null ) . setIntPref ( 'browser.sessionstore.max_windows_undo' , 0 ) ;
130+ Services . prefs . getDefaultBranch ( null ) . setBoolPref ( 'browser.shell.checkDefaultBrowser' , false ) ;
131+ Services . prefs . getDefaultBranch ( null ) . setBoolPref ( 'browser.startup.upgradeDialog.enabled' , false ) ;
120132Services . prefs . getDefaultBranch ( null ) . setBoolPref ( 'browser.privateWindowSeparation.enabled' , false ) ;
121133Services . prefs . getDefaultBranch ( null ) . setBoolPref ( 'browser.privacySegmentation.createdShortcut' , true ) ;
122134
135+ // Disable default browser prompt
136+ BrowserGlue . prototype . _maybeShowDefaultBrowserPrompt = async ( ) => null ;
137+
138+ // Disable onboarding messages
139+ OnboardingMessageProvider . getMessages = async ( ) => [ ] ;
140+ OnboardingMessageProvider . getUntranslatedMessages = async ( ) => [ ] ;
141+
123142// Override command line helper to intercept PWAsForFirefox arguments and start loading the site
124143nsDefaultCommandLineHandler . prototype . _handle = nsDefaultCommandLineHandler . prototype . handle ;
125144nsDefaultCommandLineHandler . prototype . handle = function ( cmdLine ) {
@@ -196,6 +215,118 @@ nsContentDispatchChooser.prototype._hasProtocolHandlerPermission = function(sche
196215 return this . _hasProtocolHandlerPermissionOriginal ( scheme , principal , triggeredExternally ) ;
197216} ;
198217
218+ // Handle opening new window from keyboard shortcuts
219+ BrowserWindowTracker . _openWindow = BrowserWindowTracker . openWindow ;
220+ BrowserWindowTracker . openWindow = function ( options ) {
221+ if ( options . openerWindow && options . openerWindow . gFFPWASiteConfig && ! options . args ) {
222+ options . args = Cc [ '@mozilla.org/supports-string;1' ] . createInstance ( Ci . nsISupportsString ) ;
223+ options . args . data = options . openerWindow . HomePage . get ( options . openerWindow ) ;
224+ }
225+ return BrowserWindowTracker . _openWindow ( options ) ;
226+ } ;
227+
228+ // Some checks for protocol handlers are directly based on the Firefox code, licensed under MPL 2.0
229+ // Original source: https://github.com/mozilla/gecko-dev/blob/a62618baa72cd0ba6c0a5f5fc0b1d63f2866b7c6/browser/components/protocolhandler/WebProtocolHandlerRegistrar.jsm
230+
231+ // Handle registering custom protocol handlers
232+ WebProtocolHandlerRegistrar . prototype . registerProtocolHandler = function ( protocol , url , title , documentURI , browserOrWindow ) {
233+ protocol = ( protocol || '' ) . toLowerCase ( ) ;
234+ if ( ! url || ! documentURI ) return ;
235+
236+ // Some special handling for e10s and non-e10s
237+ let browser = browserOrWindow ;
238+ if ( browserOrWindow instanceof Ci . nsIDOMWindow ) {
239+ let rootDocShell = browserOrWindow . docShell . sameTypeRootTreeItem ;
240+ browser = rootDocShell . QueryInterface ( Ci . nsIDocShell ) . chromeEventHandler ;
241+ }
242+
243+ // Get the browser window
244+ let browserWindow = browser . ownerGlobal ;
245+
246+ // Check if protocol handler is allowed
247+ try { browser . ownerGlobal . navigator . checkProtocolHandlerAllowed ( protocol , url , documentURI ) }
248+ catch ( _ ) { return }
249+
250+ // If the protocol handler is already registered, just return early
251+ // We only allow one handler (either manifest or custom) per protocol scheme
252+ const existingHandlers = new Set ( [
253+ ...browserWindow . gFFPWASiteConfig . config . custom_protocol_handlers ,
254+ ...browserWindow . gFFPWASiteConfig . manifest . protocol_handlers
255+ ] . map ( handler => lazy . sanitizeString ( handler . protocol ) ) . filter ( handler => handler ) . sort ( ) ) ;
256+ if ( existingHandlers . has ( protocol ) ) return ;
257+
258+ // Now ask the user and provide the proper callback
259+ const message = this . _getFormattedString ( 'addProtocolHandlerMessage' , [ url . host , protocol , ] ) ;
260+
261+ const notificationBox = browser . getTabBrowser ( ) . getNotificationBox ( browser ) ;
262+ const notificationIcon = url . prePath + '/favicon.ico' ;
263+ const notificationValue = 'Protocol Registration: ' + protocol ;
264+
265+ const addButton = {
266+ label : this . _getString ( 'addProtocolHandlerAddButton' ) ,
267+ accessKey : this . _getString ( 'addProtocolHandlerAddButtonAccesskey' ) ,
268+ protocolInfo : { site : browserWindow . gFFPWASiteConfig . ulid , protocol : protocol , url : url . spec } ,
269+
270+ async callback ( notification , buttonInfo ) {
271+ // Send a request to the native program to register the handler
272+ const response = await lazy . sendNativeMessage ( {
273+ cmd : 'RegisterProtocolHandler' ,
274+ params : {
275+ site : buttonInfo . protocolInfo . site ,
276+ protocol : buttonInfo . protocolInfo . protocol ,
277+ url : buttonInfo . protocolInfo . url ,
278+ }
279+ } ) ;
280+ if ( response . type === 'Error' ) throw new Error ( response . data ) ;
281+ if ( response . type !== 'ProtocolHandlerRegistered' ) throw new Error ( `Received invalid response type: ${ response . type } ` ) ;
282+
283+ // Reset the handlerInfo to ask before the next use
284+ const eps = Cc [ '@mozilla.org/uriloader/external-protocol-service;1' ] . getService ( Ci . nsIExternalProtocolService ) ;
285+ const handlerInfo = eps . getProtocolHandlerInfo ( buttonInfo . protocolInfo . protocol ) ;
286+ handlerInfo . alwaysAskBeforeHandling = true ;
287+
288+ const hs = Cc [ '@mozilla.org/uriloader/handler-service;1' ] . getService ( Ci . nsIHandlerService ) ;
289+ hs . store ( handlerInfo ) ;
290+
291+ // Hide the notification
292+ notificationBox . currentNotification . close ( ) ;
293+ } ,
294+ } ;
295+
296+ notificationBox . appendNotification (
297+ notificationValue ,
298+ {
299+ label : message ,
300+ image : notificationIcon ,
301+ priority : notificationBox . PRIORITY_INFO_LOW
302+ } ,
303+ [ addButton ]
304+ ) ;
305+ } ;
306+
307+ // Handle unregistering custom protocol handlers
308+ // Disabled for now until we figure out how to access window from here
309+ // WebProtocolHandlerRegistrar.prototype.removeProtocolHandler = function (protocol, url) {
310+ // (async () => {
311+ // // Send a request to the native program to unregister the handler
312+ // const response = await lazy.sendNativeMessage({
313+ // cmd: 'UnregisterProtocolHandler',
314+ // params: {
315+ // site: window.gFFPWASiteConfig.ulid,
316+ // protocol,
317+ // url,
318+ // }
319+ // });
320+ // if (response.type === 'Error') throw new Error(response.data);
321+ // if (response.type !== 'ProtocolHandlerUnregistered') throw new Error(`Received invalid response type: ${response.type}`);
322+ //
323+ // // Reset the handlerInfo to ask before the next use
324+ // const eps = Cc['@mozilla.org/uriloader/external-protocol-service;1'].getService(Ci.nsIExternalProtocolService);
325+ // const handlerInfo = eps.getProtocolHandlerInfo(protocol);
326+ // handlerInfo.alwaysAskBeforeHandling = true;
327+ // })()
328+ // };
329+
199330// Register a localization source for the packaged locales
200331Services . obs . addObserver ( async ( ) => {
201332 const languages = Services . locale . packagedLocales ;
0 commit comments