mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-10-29 23:35:02 -04:00 
			
		
		
		
	More work on web relay, #4172
This commit is contained in:
		
							parent
							
								
									4dd5c18db4
								
							
						
					
					
						commit
						571a0f1c2d
					
				
							
								
								
									
										143
									
								
								apprelays.js
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								apprelays.js
									
									
									
									
									
								
							| @ -19,7 +19,8 @@ Protocol numbers | ||||
| 10 = RDP | ||||
| 11 = SSH-TERM | ||||
| 12 = VNC | ||||
| 13 - SSH-FILES | ||||
| 13 = SSH-FILES | ||||
| 14 = Web-TCP | ||||
| */ | ||||
| 
 | ||||
| // Protocol Numbers
 | ||||
| @ -58,6 +59,146 @@ const MESHRIGHT_GUESTSHARING = 0x00080000; // 524288 | ||||
| const MESHRIGHT_DEVICEDETAILS = 0x00100000; // 1048576
 | ||||
| const MESHRIGHT_ADMIN = 0xFFFFFFFF; | ||||
| 
 | ||||
| 
 | ||||
| // Construct a TCP relay object
 | ||||
| module.exports.CreateTcpRelay = function (parent, db, req, args, domain) { | ||||
|     const Net = require('net'); | ||||
|     const WebSocket = require('ws'); | ||||
| 
 | ||||
|     const obj = {}; | ||||
|     obj.relayActive = false; | ||||
|     obj.closed = false; | ||||
| 
 | ||||
|     // Events
 | ||||
|     obj.ondata = null; | ||||
|     obj.onconnect = null; | ||||
|     obj.onclose = null; | ||||
| 
 | ||||
|     // Disconnect
 | ||||
|     obj.close = function (arg) { | ||||
|         if (obj.closed == true) return; | ||||
|         obj.closed = true; | ||||
| 
 | ||||
|         // Event the session ending
 | ||||
|         if ((obj.startTime) && (obj.meshid != null)) { | ||||
|             // Collect how many raw bytes where received and sent.
 | ||||
|             // We sum both the websocket and TCP client in this case.
 | ||||
|             var inTraffc = obj.ws._socket.bytesRead, outTraffc = obj.ws._socket.bytesWritten; | ||||
|             if (obj.wsClient != null) { inTraffc += obj.wsClient._socket.bytesRead; outTraffc += obj.wsClient._socket.bytesWritten; } | ||||
|             const sessionSeconds = Math.round((Date.now() - obj.startTime) / 1000); | ||||
|             const user = parent.users[obj.cookie.userid]; | ||||
|             const username = (user != null) ? user.name : null; | ||||
|             const event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, userid: obj.cookie.userid, username: username, sessionid: obj.sessionid, msgid: 123, msgArgs: [sessionSeconds, obj.sessionid], msg: "Left Web-SSH session \"" + obj.sessionid + "\" after " + sessionSeconds + " second(s).", protocol: PROTOCOL_WEBSSH, bytesin: inTraffc, bytesout: outTraffc }; | ||||
|             parent.parent.DispatchEvent(['*', obj.nodeid, obj.cookie.userid, obj.meshid], obj, event); | ||||
|             delete obj.startTime; | ||||
|             delete obj.sessionid; | ||||
|         } | ||||
|         if (obj.wsClient) { | ||||
|             obj.wsClient.removeAllListeners('open'); | ||||
|             obj.wsClient.removeAllListeners('message'); | ||||
|             obj.wsClient.removeAllListeners('close'); | ||||
|             try { obj.wsClient.close(); } catch (ex) { console.log(ex); } | ||||
|             delete obj.wsClient; | ||||
|         } | ||||
| 
 | ||||
|         if ((arg == 1) || (arg == null)) { try { ws.close(); } catch (ex) { console.log(ex); } } // Soft close, close the websocket
 | ||||
|         if (arg == 2) { try { ws._socket._parent.end(); } catch (ex) { console.log(ex); } } // Hard close, close the TCP socket
 | ||||
|         obj.ws.removeAllListeners(); | ||||
| 
 | ||||
|         // Event disconnection
 | ||||
|         if (obj.onclose) { obj.onclose(); } | ||||
| 
 | ||||
|         obj.relayActive = false; | ||||
|         delete obj.cookie; | ||||
|         delete obj.nodeid; | ||||
|         delete obj.meshid; | ||||
|         delete obj.userid; | ||||
|     }; | ||||
| 
 | ||||
|     // Start the looppback server
 | ||||
|     function startRelayConnection() { | ||||
|         try { | ||||
|             // Setup the correct URL with domain and use TLS only if needed.
 | ||||
|             const options = { rejectUnauthorized: false }; | ||||
|             const protocol = (args.tlsoffload) ? 'ws' : 'wss'; | ||||
|             var domainadd = ''; | ||||
|             if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' } | ||||
|             const url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=14&auth=' + obj.xcookie; // Protocol 14 is Web-TCP
 | ||||
|             parent.parent.debug('relay', 'TCP: Connection websocket to ' + url); | ||||
|             obj.wsClient = new WebSocket(url, options); | ||||
|             obj.wsClient.on('open', function () { parent.parent.debug('relay', 'TCP: Relay websocket open'); }); | ||||
|             obj.wsClient.on('message', function (data) { // Make sure to handle flow control.
 | ||||
|                 if (obj.relayActive == false) { | ||||
|                     if ((data == 'c') || (data == 'cr')) { | ||||
|                         obj.relayActive = true; | ||||
|                         if (obj.onconnect) { obj.onconnect(); } // Event connection
 | ||||
|                     } | ||||
|                 } else { | ||||
|                     if (typeof data == 'string') { | ||||
|                         // Forward any ping/pong commands to the browser
 | ||||
|                         var cmd = null; | ||||
|                         try { cmd = JSON.parse(data); } catch (ex) { } | ||||
|                         if ((cmd != null) && (cmd.ctrlChannel == '102938') && (cmd.type == 'ping')) { cmd.type = 'pong'; obj.wsClient.send(JSON.stringify(cmd)); } | ||||
|                         return; | ||||
|                     } | ||||
|                     // Relay WS --> TCP, event data coming in
 | ||||
|                     if (obj.ondata) { obj.ondata(data); } | ||||
|                 } | ||||
|             }); | ||||
|             obj.wsClient.on('close', function () { parent.parent.debug('relay', 'TCP: Relay websocket closed'); obj.close(); }); | ||||
|             obj.wsClient.on('error', function (err) { parent.parent.debug('relay', 'TCP: Relay websocket error: ' + err); obj.close(); }); | ||||
|         } catch (ex) { | ||||
|             console.log(ex); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Send data thru the relay tunnel
 | ||||
|     obj.send = function (data) { | ||||
|         if (obj.relayActive = - false) return false; | ||||
|         obj.wsClient.send(data); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     parent.parent.debug('relay', 'TCP: Request for TCP relay (' + req.clientIp + ')'); | ||||
| 
 | ||||
|     // Decode the authentication cookie
 | ||||
|     obj.cookie = parent.parent.decodeCookie(req.query.auth, parent.parent.loginCookieEncryptionKey); | ||||
|     if ((obj.cookie == null) || (obj.cookie.userid == null) || (parent.users[obj.cookie.userid] == null)) { obj.ws.send(JSON.stringify({ action: 'sessionerror' })); obj.close(); return; } | ||||
|     obj.userid = obj.cookie.userid; | ||||
| 
 | ||||
|     // Get the meshid for this device
 | ||||
|     parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) { | ||||
|         if (obj.cookie == null) return; // obj has been cleaned up, just exit.
 | ||||
|         if ((err != null) || (nodes == null) || (nodes.length != 1)) { parent.parent.debug('relay', 'TCP: Invalid device'); obj.close(); } | ||||
|         const node = nodes[0]; | ||||
|         obj.nodeid = node._id; // Store the NodeID
 | ||||
|         obj.meshid = node.meshid; // Store the MeshID
 | ||||
|         obj.mtype = node.mtype; // Store the device group type
 | ||||
| 
 | ||||
|         // Check if we need to relay thru a different agent
 | ||||
|         const mesh = parent.meshes[obj.meshid]; | ||||
|         if (mesh && mesh.relayid) { | ||||
|             obj.relaynodeid = mesh.relayid; | ||||
|             obj.tcpaddr = node.host; | ||||
| 
 | ||||
|             // Check if we have rights to the relayid device, does nothing if a relay is not used
 | ||||
|             checkRelayRights(parent, domain, obj.cookie.userid, obj.relaynodeid, function (allowed) { | ||||
|                 if (obj.cookie == null) return; // obj has been cleaned up, just exit.
 | ||||
|                 if (allowed !== true) { parent.parent.debug('relay', 'TCP: Attempt to use un-authorized relay'); obj.close(); return; } | ||||
| 
 | ||||
|                 // Re-encode a cookie with a device relay
 | ||||
|                 const cookieContent = { userid: obj.cookie.userid, domainid: obj.cookie.domainid, nodeid: mesh.relayid, tcpaddr: node.host, tcpport: obj.cookie.tcpport }; | ||||
|                 obj.xcookie = parent.parent.encodeCookie(cookieContent, parent.parent.loginCookieEncryptionKey); | ||||
|             }); | ||||
|         } else { | ||||
|             obj.xcookie = req.query.auth; | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
|     return obj; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| // Construct a MSTSC Relay object, called upon connection
 | ||||
| // This implementation does not have TLS support
 | ||||
| // This is a bit of a hack as we are going to run the RDP connection thru a loopback connection.
 | ||||
|  | ||||
| @ -43,6 +43,8 @@ const MESHRIGHT_ADMIN = 0xFFFFFFFF; | ||||
| // 10 = Web-RDP
 | ||||
| // 11 = Web-SSH
 | ||||
| // 12 = Web-VNC
 | ||||
| // 13 = Web-SSH-Files
 | ||||
| // 14 = Web-TCP
 | ||||
| // 100 = Intel AMT WSMAN
 | ||||
| // 101 = Intel AMT Redirection
 | ||||
| // 200 = Messenger
 | ||||
|  | ||||
| @ -1449,6 +1449,7 @@ | ||||
|         var features = parseInt('{{{features}}}'); | ||||
|         var features2 = parseInt('{{{features2}}}'); | ||||
|         var sessionTime = parseInt('{{{sessiontime}}}'); | ||||
|         var webRelayPort = parseInt('{{{webRelayPort}}}'); | ||||
|         var sessionRefreshTimer = null; | ||||
|         var domain = '{{{domain}}}'; | ||||
|         var domainUrl = '{{{domainurl}}}'; | ||||
| @ -2737,7 +2738,7 @@ | ||||
|                         if (message.name != null) { url += ('&name=' + encodeURIComponentEx(message.name)); } | ||||
|                         if (message.ip != null) { url += ('&remoteip=' + message.ip); } | ||||
|                         url += ('&appid=' + message.protocol + '&autoexit=1'); // Protocol: 0 = Custom, 1 = HTTP, 2 = HTTPS, 3 = RDP, 4 = PuTTY, 5 = WinSCP, 6 = MCRDesktop, 7 = MCRFiles | ||||
|                         console.log(url); | ||||
|                         //console.log(url); | ||||
|                         downloadFile(url, ''); | ||||
|                     } else if (message.tag == 'novnc') { | ||||
|                         var vncurl = window.location.origin + domainUrl + 'novnc/vnc.html?ws=wss%3A%2F%2F' + window.location.host + encodeURIComponentEx(domainUrl) + (message.localRelay?'local':'mesh') + 'relay.ashx%3Fauth%3D' + message.cookie + '&show_dot=1' + (urlargs.key?('&key=' + urlargs.key):'') + '&l={{{lang}}}'; | ||||
| @ -4573,6 +4574,10 @@ | ||||
| 
 | ||||
|             // RDP link, show this link only of the remote machine is Windows. | ||||
|             if ((((node.conn & 1) != 0) || (node.mtype == 3)) && (node.agent) && ((meshrights & 8) != 0) && (node.agent.id != 14)) { | ||||
|                 if (webRelayPort != 0) { | ||||
|                     x += '<a href=# onclick=p10WebRouter("' + node._id + '",1,80)>' + "HTTP" + '</a> '; | ||||
|                     //x += '<a href=# onclick=p10WebRouter("' + node._id + '",2,443)>' + "HTTPS" + '</a> '; | ||||
|                 } | ||||
|                 if ((node.agent.id > 0) && (node.agent.id < 5)) { | ||||
|                     if (navigator.platform.toLowerCase() == 'win32') { | ||||
|                         if ((serverinfo.devicemeshrouterlinks == null) || (serverinfo.devicemeshrouterlinks.rdp != false)) { | ||||
| @ -7141,6 +7146,10 @@ | ||||
| 
 | ||||
|                     // RDP link, show this link only of the remote machine is Windows. | ||||
|                     if ((((connectivity & 1) != 0) || (node.mtype == 3)) && (node.agent) && ((meshrights & 8) != 0)) { | ||||
|                         if (webRelayPort != 0) { | ||||
|                             x += '<a href=# onclick=p10WebRouter("' + node._id + '",1,80)>' + "HTTP" + '</a> '; | ||||
|                             //x += '<a href=# onclick=p10WebRouter("' + node._id + '",2,443)>' + "HTTPS" + '</a> '; | ||||
|                         } | ||||
|                         if ((node.agent.id > 0) && (node.agent.id < 5)) { | ||||
|                             if (navigator.platform.toLowerCase() == 'win32') { | ||||
|                                 if ((serverinfo.devicemeshrouterlinks == null) || (serverinfo.devicemeshrouterlinks.rdp != false)) { | ||||
| @ -8063,6 +8072,22 @@ | ||||
|             meshserver.send({ action: 'removedevices', nodeids: [ nodeid ] }); | ||||
|         } | ||||
| 
 | ||||
|         function p10WebRouter(nodeid, protocol, port, addr) { | ||||
|             var relayid = null; | ||||
|             var node = getNodeFromId(nodeid); | ||||
|             if (node.mtype == 3) { // Setup device relay if needed | ||||
|                 var mesh = meshes[node.meshid]; | ||||
|                 if (mesh && mesh.relayid) { relayid = mesh.relayid; addr = node.host; } | ||||
|             } | ||||
|             var servername = serverinfo.name; | ||||
|             if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name. | ||||
|             var url = 'https://' + servername + ':' + webRelayPort + '/control-redirect.ashx?n=' + nodeid + '&p=' + port + '&appid=' + protocol; // Protocol: 1 = HTTP, 2 = HTTPS | ||||
|             if (addr != null) { url += '&addr=' + addr; } | ||||
|             if (relayid != null) { url += '&relayid=' + relayid; } | ||||
|             safeNewWindow(url, 'WebRelay'); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         function p10MCRouter(nodeid, protocol, port, addr, localport) { | ||||
|             var node = getNodeFromId(nodeid); | ||||
|             var mesh = meshes[node.meshid]; | ||||
|  | ||||
| @ -24,11 +24,35 @@ module.exports.CreateWebRelayServer = function (parent, db, args, certificates, | ||||
|     obj.net = require('net'); | ||||
|     obj.app = obj.express(); | ||||
|     obj.webRelayServer = null; | ||||
|     obj.port = null; | ||||
|     obj.port = 0; | ||||
|     obj.relayTunnels = {}             // RelayID --> Web Tunnel
 | ||||
|     const constants = (require('crypto').constants ? require('crypto').constants : require('constants')); // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead.
 | ||||
|     var tlsSessionStore = {};         // Store TLS session information for quick resume.
 | ||||
|     var tlsSessionStoreCount = 0;     // Number of cached TLS session information in store.
 | ||||
| 
 | ||||
|     if (args.trustedproxy) { | ||||
|         // Reverse proxy should add the "X-Forwarded-*" headers
 | ||||
|         try { | ||||
|             obj.app.set('trust proxy', args.trustedproxy); | ||||
|         } catch (ex) { | ||||
|             // If there is an error, try to resolve the string
 | ||||
|             if ((args.trustedproxy.length == 1) && (typeof args.trustedproxy[0] == 'string')) { | ||||
|                 require('dns').lookup(args.trustedproxy[0], function (err, address, family) { if (err == null) { obj.app.set('trust proxy', address); args.trustedproxy = [address]; } }); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     else if (typeof args.tlsoffload == 'object') { | ||||
|         // Reverse proxy should add the "X-Forwarded-*" headers
 | ||||
|         try { | ||||
|             obj.app.set('trust proxy', args.tlsoffload); | ||||
|         } catch (ex) { | ||||
|             // If there is an error, try to resolve the string
 | ||||
|             if ((Array.isArray(args.tlsoffload)) && (args.tlsoffload.length == 1) && (typeof args.tlsoffload[0] == 'string')) { | ||||
|                 require('dns').lookup(args.tlsoffload[0], function (err, address, family) { if (err == null) { obj.app.set('trust proxy', address); args.tlsoffload = [address]; } }); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Add HTTP security headers to all responses
 | ||||
|     obj.app.use(function (req, res, next) { | ||||
|         parent.debug('webrequest', req.url + ' (RelayServer)'); | ||||
| @ -41,9 +65,50 @@ module.exports.CreateWebRelayServer = function (parent, db, args, certificates, | ||||
|             'X-Content-Type-Options': 'nosniff', | ||||
|             'Content-Security-Policy': "default-src 'none'; style-src 'self' 'unsafe-inline';" | ||||
|         }); | ||||
| 
 | ||||
|         // Set the real IP address of the request
 | ||||
|         // If a trusted reverse-proxy is sending us the remote IP address, use it.
 | ||||
|         var ipex = '0.0.0.0', xforwardedhost = req.headers.host; | ||||
|         if (typeof req.connection.remoteAddress == 'string') { ipex = (req.connection.remoteAddress.startsWith('::ffff:')) ? req.connection.remoteAddress.substring(7) : req.connection.remoteAddress; } | ||||
|         if ( | ||||
|             (args.trustedproxy === true) || (args.tlsoffload === true) || | ||||
|             ((typeof args.trustedproxy == 'object') && (isIPMatch(ipex, args.trustedproxy))) || | ||||
|             ((typeof args.tlsoffload == 'object') && (isIPMatch(ipex, args.tlsoffload))) | ||||
|         ) { | ||||
|             // Get client IP
 | ||||
|             if (req.headers['cf-connecting-ip']) { // Use CloudFlare IP address if present
 | ||||
|                 req.clientIp = req.headers['cf-connecting-ip'].split(',')[0].trim(); | ||||
|             } else if (req.headers['x-forwarded-for']) { | ||||
|                 req.clientIp = req.headers['x-forwarded-for'].split(',')[0].trim(); | ||||
|             } else if (req.headers['x-real-ip']) { | ||||
|                 req.clientIp = req.headers['x-real-ip'].split(',')[0].trim(); | ||||
|             } else { | ||||
|                 req.clientIp = ipex; | ||||
|             } | ||||
| 
 | ||||
|             // If there is a port number, remove it. This will only work for IPv4, but nice for people that have a bad reverse proxy config.
 | ||||
|             const clientIpSplit = req.clientIp.split(':'); | ||||
|             if (clientIpSplit.length == 2) { req.clientIp = clientIpSplit[0]; } | ||||
| 
 | ||||
|             // Get server host
 | ||||
|             if (req.headers['x-forwarded-host']) { xforwardedhost = req.headers['x-forwarded-host'].split(',')[0]; } // If multiple hosts are specified with a comma, take the first one.
 | ||||
|         } else { | ||||
|             req.clientIp = ipex; | ||||
|         } | ||||
| 
 | ||||
|         return next(); | ||||
|     }); | ||||
| 
 | ||||
|     // This is the magic URL that will setup the relay session
 | ||||
|     obj.app.get('/control-redirect.ashx', function (req, res) { | ||||
|         res.set({ 'Cache-Control': 'no-store' }); | ||||
|         parent.debug('web', 'webRelaySetup'); | ||||
| 
 | ||||
|         console.log('req.query', req.query); | ||||
| 
 | ||||
|         res.redirect('/'); | ||||
|     }); | ||||
| 
 | ||||
|     // Start the server, only after users and meshes are loaded from the database.
 | ||||
|     if (args.tlsoffload) { | ||||
|         // Setup the HTTP server without TLS
 | ||||
| @ -86,6 +151,7 @@ module.exports.CreateWebRelayServer = function (parent, db, args, certificates, | ||||
|             obj.parent.updateServerState('http-relay-port', port); | ||||
|             if (args.aliasport != null) { obj.parent.updateServerState('http-relay-aliasport', args.aliasport); } | ||||
|         } | ||||
|         obj.port = port; | ||||
|     } | ||||
| 
 | ||||
|     CheckListenPort(args.relayport, args.relayportbind, StartWebRelayServer); | ||||
|  | ||||
							
								
								
									
										13
									
								
								webserver.js
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								webserver.js
									
									
									
									
									
								
							| @ -2858,7 +2858,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF | ||||
|                     footer: (domain.footer == null) ? '' : domain.footer, | ||||
|                     webstate: encodeURIComponent(webstate).replace(/'/g, '%27'), | ||||
|                     amtscanoptions: amtscanoptions, | ||||
|                     pluginHandler: (parent.pluginHandler == null) ? 'null' : parent.pluginHandler.prepExports() | ||||
|                     pluginHandler: (parent.pluginHandler == null) ? 'null' : parent.pluginHandler.prepExports(), | ||||
|                     webRelayPort: ((parent.webrelayserver != null) ? parent.webrelayserver.port : 0) | ||||
|                 }, dbGetFunc.req, domain), user); | ||||
|             } | ||||
|             xdbGetFunc.req = req; | ||||
| @ -5846,11 +5847,19 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF | ||||
|             var selfurl = ' wss://' + req.headers.host; | ||||
|             if ((xforwardedhost != null) && (xforwardedhost != req.headers.host)) { selfurl += ' wss://' + xforwardedhost; } | ||||
|             const extraScriptSrc = (parent.config.settings.extrascriptsrc != null) ? (' ' + parent.config.settings.extrascriptsrc) : ''; | ||||
| 
 | ||||
|             // If the web relay port is enabled, allow the web page to redirect to it
 | ||||
|             var extraFrameSrc = ''; | ||||
|             if ((parent.webrelayserver != null) && (parent.webrelayserver.port != 0)) { | ||||
|                 extraFrameSrc = ' https://' + req.headers.host + ':' + parent.webrelayserver.port; | ||||
|                 if ((xforwardedhost != null) && (xforwardedhost != req.headers.host)) { extraFrameSrc += ' https://' + xforwardedhost + ':' + parent.webrelayserver.port; } | ||||
|             } | ||||
| 
 | ||||
|             const headers = { | ||||
|                 'Referrer-Policy': 'no-referrer', | ||||
|                 'X-XSS-Protection': '1; mode=block', | ||||
|                 'X-Content-Type-Options': 'nosniff', | ||||
|                 'Content-Security-Policy': "default-src 'none'; font-src 'self'; script-src 'self' 'unsafe-inline'" + extraScriptSrc + "; connect-src 'self'" + geourl + selfurl + "; img-src 'self' blob: data:" + geourl + " data:; style-src 'self' 'unsafe-inline'; frame-src 'self' mcrouter:; media-src 'self'; form-action 'self'" | ||||
|                 'Content-Security-Policy': "default-src 'none'; font-src 'self'; script-src 'self' 'unsafe-inline'" + extraScriptSrc + "; connect-src 'self'" + geourl + selfurl + "; img-src 'self' blob: data:" + geourl + " data:; style-src 'self' 'unsafe-inline'; frame-src 'self' mcrouter:" + extraFrameSrc + "; media-src 'self'; form-action 'self'" | ||||
|             }; | ||||
|             if (req.headers['user-agent'] && (req.headers['user-agent'].indexOf('Chrome') >= 0)) { headers['Permissions-Policy'] = 'interest-cohort=()'; } // Remove Google's FLoC Network, only send this if Chrome browser
 | ||||
|             if ((parent.config.settings.allowframing !== true) && (typeof parent.config.settings.allowframing !== 'string')) { headers['X-Frame-Options'] = 'sameorigin'; } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user