Google Analytics Via Node.js Proxy - node.js

I am trying to impliment a proxy for google analytics into my current site. I started by following this guide.
After following all the steps I get a 400 error returned from google with no further information.
I downloaded google's analytics.js file and put it on my server, and replaced all instances of www.google-analytics.com with "+location.host+"/analytics. See the file here: https://pastebin.com/wimHim7x
I edited my tracking code from google to replace 'https://www.google-analytics.com/analytics.js' with '/analytics.js'.
Here is the proxy info from my app.js file
function getIpFromReq (req) { // get the client's IP address
var bareIP = ":" + ((req.connection.socket && req.connection.socket.remoteAddress)
|| req.headers["x-forwarded-for"] || req.connection.remoteAddress || "");
return (bareIP.match(/:([^:]+)$/) || [])[1] || "127.0.0.1";
}
// proxying requests from /analytics to www.google-analytics.com.
app.use("/analytics", proxy("www.google-analytics.com", {
proxyReqPathResolver: function (req) {
var path = req.url + (req.url.indexOf("?") === -1 ? "?" : "&")
+ "uip=" + encodeURIComponent(getIpFromReq(req));
console.log(path)
return path;
}
}));
This is the page I get returned from google:
<!DOCTYPE html>
<html lang=en>
<meta charset=utf-8>
<meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
<title>Error 400 (Bad Request)!!1</title>
<style>
*{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}#media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}#media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}#media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}
</style>
<a href=//www.google.com/><span id=logo aria-label=Google></span></a>
<p><b>400.</b> <ins>That’s an error.</ins>
<p>Your client has issued a malformed or illegal request. <ins>That’s all we know.</ins>

Related

routing a webpage error, nodejs and expressjs

I am trying to route directly to the html file using express.js, getting an unknown error, being new to express.js, I couldn't get how to resolve this one:-
here is the js code :-
const express = require('express');
const path = require();
const app = express();
const port=process.env.PORT || 8000;
// public static path
const static_path = path.join(__dirname,"../public");
app.use(express.static(static_path));
app.get("",(req,res)=>{
res.send("welcome to this main page");
})
app.get("/about",(req,res)=>{
res.send("welcome to this about page");
})
app.get("/weather",(req,res)=>{
res.send("welcome to this weather page");
})
app.get("*",(req,res)=>{
res.send("404 Error page oops");
})
app.listen(port,()=>{
console.log(`listening to the port ${port}`);
})
static web page:-
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Weather App</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h1>Welcome to the static web</h1>
</body>
</html>
getting this error:-
internal/validators.js:124
throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
^
TypeError [ERR_INVALID_ARG_TYPE]: The "id" argument must be of type string. Received undefined
ok, I was using "type nul > filename" command for creating new files in attached folders. When I used directly the VSCode feature of creating files, it's working fine now,... don't know why, but I think that old command might have expired, tell me if I am wrong, but I just solved my issue...

Office.js Office.context.ui.messageParent not working in Excel

We have an excel add-in hosted in azure where the Office.context.ui.messageParent API messages aren't being sent/received on the desktop. There's no errors, the message just doesn't get caught at the event listener.
We use the dialog for MFA and we have it working locally for both desktop and web but when we deploy to a stage add-in hosted in azure this issue occurs just on the desktop.
This works:
dialog url (https://localhost:3000/dist/callback.html)
taskpane url (https://localhost:3000/dist/taskpane.html)
This doesn't:
dialog url (https://ip-dev-custom-functions.azurewebsites.net/addin/callback.html)
taskpane url (https://ip-dev-custom-functions.azurewebsites.net/addin/taskpane.html)
Surprisingly the DialogEventReceived is being triggered but not the message DialogMessageReceived.
callback.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
<meta http-equiv="Expires" content="0"/>
<meta http-equiv="Cache-Control" content="private, no-cache, no-store"/>
<meta http-equiv="Pragma" content="no-cache"/>
<meta http-equiv="Expires" content="-1"/>
<title></title>
<script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js"></script>
</head>
<body>
<script>
if (window.opener)
window.opener.postMessage({type: 'interstitial', url: document.location.href}, "*");
Office.initialize = function (reason) {
console.log("Sending auth complete message through dialog: " + document.location.href);
Office.context.ui.messageParent(document.location.href);
}
</script>
</body>
</html>
snippet of the taskpane.html where's the event listener:
Office.context.ui.displayDialogAsync(url, {
height: dim.height,
width: dim.width,
promptBeforeOpen: false
}, async (result) => {
_loginDialog = result.value;
_loginDialog.addEventHandler(Office.EventType.DialogMessageReceived, processMessage);
_loginDialog.addEventHandler(Office.EventType.DialogEventReceived, (ev) => {
console.log("## EVENT RECEIVED ##", ev);
});
});
function processMessage(arg) {
console.log("Message received in processMessage: " + JSON.stringify(arg));
_lastCallback(arg.message);
_loginDialog?.close();
_loginDialog = null;
}
Based on Authenticate and authorize with the Office dialog API, the correct flow is:
The add-in should launch the page in the dialog in add-in's domain, then redirect to the sign-in page, and then redirect to another page with the same domain as the first page in dialog again.
Otherwise, the messageParent API won't work, because it only trust the domain of the page used in the displayDialogAsync() API. In your scenario, the sign-in page (launched first time in the dialog) and the callback page are in different domains, which causes the problem.
Thanks.

WebChat - Direct Line Speech adapter error: WebSocket connection failed with 400

I have a Bot service running on Azure. I'm trying to voice enable the bot, however I keep getting Websocket connection error.
I have the echo-bot running on the server side. I followed this tutorial and I added a Direct Line Speech channel to the bot with a cognitive speech service on Azure portal.
As the client, I used the sample Direct Line Speech sample. Here is the full code:
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<script
crossorigin="anonymous"
src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<title>Speech Test</title>
<style>
html,
body {
height: 100%;
}
body {
margin: 0;
}
#webchat {
height: 100%;
width: 100%;
}
</style>
</head>
<body >
<div id="root"></div>
<div id="webchat" role="main"></div>
<script>
(async function () {
async function fetchCredentials(){
const res = await fetch(
"https://westeurope.api.cognitive.microsoft.com/sts/v1.0/issueToken",
{
method: "POST",
headers: {
"Ocp-Apim-Subscription-Key": `XXXXXXXXX`,
},
}
);
if (!res.ok) {
throw new Error("Failed to fetch authorization token and region.");
}
return { authorizationToken: await res.text(), region: "westeurope" };
};
const adapters = await window.WebChat.createDirectLineSpeechAdapters({
fetchCredentials
});
window.WebChat.renderWebChat(
{
...adapters
},
document.getElementById("webchat")
);
document.querySelector("#webchat > *").focus();
})().catch((err) => err);
</script>
</body>
</html>
What might be the reason for Websocket to fail? I appreciate any help.
Version
<meta name="botframework-directlinespeech:version" content="4.11.0">
<meta name="botframework-webchat:bundle:variant" content="full">
<meta name="botframework-webchat:bundle:version" content="4.11.0">
<meta name="botframework-webchat:core:version" content="4.11.0">
<meta name="botframework-webchat:ui:version" content="4.11.0">
Error
Firefox can’t establish a connection to the server at wss://westeurope.convai.speech.microsoft.com/api/v3?language=en-US&format=simple&Authorization=<XXXXXXXXXXXX>&X-ConnectionId=7047B4CE339E4DFDA5435664DEF8CE58
could you please check if following troubleshooting guidance works? https://learn.microsoft.com/en-us/azure/cognitive-services/Speech-Service/troubleshooting#error-websocket-upgrade-failed-with-an-authentication-error-403
It says Error: HTTP 400 Bad Request is an error usually occurs when the request body contains invalid audio data. Only WAV format is supported. Also, check the request's headers to make sure you specify appropriate values for Content-Type and Content-Length.

How to expose a static html page from ionic

I have a static html page which intercept authorization message, I'd like to expose this on the domain. It looks like so:
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>JwtAuthDemo - Facebook Auth</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="assets/util.js"></script>
</head>
<body>
<script>
// if we don't receive an access token then login failed and/or the user has not connected properly
var accessToken = getParameterByName("access_token");
var message = {};
if (accessToken) {
message.status = true;
message.accessToken = accessToken;
}
else
{
message.status = false;
message.error = getParameterByName("error");
message.errorDescription = getParameterByName("error_description");
}
window.opener.postMessage(JSON.stringify(message), "http://localhost:5000");
</script>
</body>
</html>
If I place this page next to the index.html page it is not exposed, however when I place it inside the assets folder it can be access. I'm guessing I have to explicitly expose the page in one of the json config files however I'm not to sure how to do so?
I'd prefer not to have my redirect url be www.mydomain.com/assets/oauth-response-parser.html. I'd like to keep this in my application seeing as it's part of the application.
How can I expose a static html page from Ionic as a sibling to the index.html page ?
You can automatically get files to your assets directory by specifying that you want to run a custom script during your ionic builds.
In your package.json you'd have a 'config' section where you can specify this script:
...
"config": {
"ionic_copy": "./config/customCopy.config.js"
},
...
and then your customCopy.config.js would contain an entry to copy over your html into assets:
module.exports = {
copyAssets: {
src: ['{{SRC}}/assets/**/*'],
dest: '{{WWW}}/assets'
}
}
More info on this process at the ionic app scripts page
I hope this steers you in the right direction.

Working with basic Node OAuth redirect following

Still confused about one point with node.
I’ve got a server running at http://localhost:3030 to listen for the hit from the redirect, but the redirect never comes.
How, in Node, do you have the request actually follow the redirects. And end up at
http://localhost:3030/?code=ccf3d214669645f594b59be14032e20d
Here is the link; In the browser it does end up in the right place
https://www.instagram.com/oauth/authorize/?client_id=8901edf0746b460489427434ba5d321e&redirect_uri=http://localhost:3030&response_type=code
The authorization_code flow requires a browser, because the user have to be redirected to the third party web site to log in and authenticate your app, in this case that's the Instagram website. So you do need a browser to redirect you back to your redirect_url with the code parameter.
For that type of OAuth flow you can use Grant. You don't have to implement the OAuth flow by yourself. Just follow the basic example and replace facebook with instagram. As you can see you have a basic web server there and you have to navigate to the /connect/instagram route in your web browser. The only difference is that Grant will handle the heavy lifting for you, so you'll receive just the access_token at the end.
You can test the Instagram flow here.
My first answer and comments are still valid, but I'm going to show you how you can automate the authorization process with nwjs.
First you need to enable the Implicit flow for your OAuth app - under the Security tab.
For the purpose of this demo I'm using http://localhost:3000/callback as redirect URI for my OAuth app. So you need to add it as additional redirect URL of your OAuth app. Also fill in all of the required credentials in authorization.html.
server.js
var fs = require('fs')
var path = require('path')
var http = require('http')
var url = require('url')
var qs = require('querystring')
var child = require('child_process')
var nw = null
var server = http.createServer()
server.on('request', function (req, res) {
if (req.url == '/connect') {
var dpath = path.resolve(__dirname)
nw = child.spawn('nw', [dpath])
res.end()
}
else if (req.url == '/callback') {
var fpath = path.resolve(__dirname, 'token.html')
var body = fs.readFileSync(fpath, 'utf8')
res.writeHead(200, {'content-type': 'text/html'})
res.end(body)
}
else if (/^\/token/.test(req.url)) {
var uri = url.parse(req.url)
var query = qs.parse(uri.query)
console.log(query)
nw.on('close', function (code, signal) {
console.log('NW closed')
})
nw.kill('SIGHUP')
res.end()
}
})
server.listen(3000, function () {
console.log('HTTP server listening on port ' + 3000)
})
Start it with:
node server.js
Then navigate to http://localhost:3000/connect, you can use your browser for now.
authorize.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Client Side Implicit OAuth Flow</title>
<script type="text/javascript" charset="utf-8">
var config = {
client_id: '[CLIENT_ID]',
redirect_uri: '[REDIRECT_URL]',
username: '[USERNAME]',
password: '[PASSWORD]'
}
var authorize_url = 'https://www.instagram.com/oauth/authorize/?' +
'client_id=' + config.client_id + '&' +
'redirect_uri=' + config.redirect_uri + '&' +
'response_type=token'
document.addEventListener('DOMContentLoaded', function (e) {
var iframe = document.querySelector('iframe')
iframe.setAttribute('src', authorize_url)
iframe.onload = function (e) {
var doc = this.contentWindow.document
// login
if (doc.querySelector('[name=username]')) {
doc.querySelector('[name=username]').value = config.username
doc.querySelector('[name=password]').value = config.password
doc.querySelector('[type=submit]').click()
}
// authorize
else if (doc.querySelector('[value=Authorize]')) {
doc.querySelector('[value=Authorize]').click()
}
}
}, false)
</script>
</head>
<body>
<iframe src=""></iframe>
</body>
</html>
Once you hit that route a new process is spawned and the authorize.html is executed. Just keep in mind that NWjs requires some graphical libraries to be installed on your server, so it's not exactly a headless browser.
There the browser navigates to the authorization URL inside an iframe. Depending on whether you are logged in or already authorized the app different pages are loaded. This code just fills in your user name and password and clicks on a few links.
Once the OAuth flow is complete you get the access_token as hash in the URL. As you may know the browser doesn't send that part of the URL to the server, so in the /callback route the server returns another page called token.html which sole purpose is to extract the access token from the URL hash and return it as a querystring in the /token route.
token.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Client Side Implicit OAuth Flow</title>
<script type="text/javascript" charset="utf-8">
var config = {
callback_uri: 'http://localhost:3000/token'
}
var access_token = window.location.hash.replace('#access_token=', '')
var url = config.callback_uri + '?access_token=' + access_token
window.location.href = url
</script>
</head>
<body>
</body>
</html>
After you run this example you'll see your access token in the command line:
$ node server.js
HTTP server listening on port 3000
{ access_token: '1404767371.e5610d0.3381e9a2fd7340d8b90b729f407949d2' }
NW closed
You can download all files from here.

Resources