Answers to this question explain how to route sub domains in Node.js with Express.
I want to know how to do it without Express.
Here's my server module, which returns a server object:
module.exports.serve = function(port) {
var server = https.createServer(options, function(req, res) {
// Parse & process URL
var reqInfo = url.parse(req.url, true, true),
path = reqInfo.pathname;
debug.log("Client [" + req.connection.remoteAddress +
"]requesting resource: " + path);
// Quickly handle preloaded requests
if (preloaded[path])
preloadReqHandler(req, res, preloaded[path], path);
// Handle general requests
else generalReqHandler(req, res, reqInfo);
}).listen(port);
return server;
};
No need to go into detail with the modules that handle the requests, I'm just interested in how to detect www.example.com and route it to example.com or vice-versa, via my server.
Just to add as much detail as possible, my goal here is to route all traffic from http://www.example.com and http://example.com and https://www.example.com and send it all to https://example.com. To do that, I think I just need to learn how to route the www sub domain, and then listen on both the http and https ports for that routing.
Since HTTP 1.1, user agents send the Host request header which specifies the domain. So you can get the domain (including the port if specified) from req.headers['host'] and apply your custom domain routing logic.
If you're talking with a HTTP 1.0 or older user agent, then just reply with "505 HTTP Version Not Supported" or serve some default content.
Related
I believe I am missing a fundimental part of the proxy set up here but when using the following:
var http = require('http'),
httpProxy = require('http-proxy');
httpProxy.createProxyServer({target:'http://www.asos.com'}).listen(8000);
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
To be presented by:
Invalid URL
The requested URL "[no URL]", is invalid.
Reference #9.56731002.1508760714.1524ffde
now I am pretty sure this is a url entered into the proxy?
All I want to do is setup up a proxy to a site and then insert some custom js file. But this is step one.
Contrary to what you've said in the comments you were correct to try to access localhost:8000. That is the correct port for the proxy you created.
You need to add this:
changeOrigin: true
In full:
httpProxy.createProxyServer({
changeOrigin: true,
target: 'http://www.asos.com'
}).listen(8000);
Without that setting the remote server will be receiving a request with the header Host: localhost:8000 and it seems that this particular server cares about the Host header (perhaps it's using virtual hosts). As a result it won't know what to do with it and it's returning that error. The proxy is successfully proxying the error message from the remote server.
You've clearly copied your code from the http-proxy documentation but you seem to have misunderstood it. Notice that in the original example the proxy target is localhost:9000, which is the same server it subsequently creates. So the intention of that example is that you will access localhost:8000 and it will proxy the request to localhost:9000. What you've trying to do is quite different. Your code is creating two completely independent servers, one on port 8000 and one on port 9000.
Rather than using the listen method you might be better off looking at the examples for the web method.
I was needed to redirect http to https and found this code:
app.enable('trust proxy');
app.use((req, res, next) => {
if (req.secure) {
next();
} else {
res.redirect('https://' + req.headers.host + req.url);
}
});
I'm using heroku to host my project, I noticed that heroku as default issued *.herokuapp.com cert, so I can use http and https as well.
When looked at req.secure within app.use callback, without app.enable('trust proxy'), req.secure is always false, when I add app.enable('trust proxy') it's false for about 2 times and after the https redirection it's switches to true.
app.enable('trust proxy'), the docs:
Indicates the app is behind a front-facing proxy, and to use the
X-Forwarded-* headers to determine the connection and the IP address
of the client.
My question:
Why would my server be behind a proxy?(is it relates to the issued *.herokuapp.com cert?), if someone could explain how all fits together, I mean, why my server is behind a proxy? and why without app.enable express won't identify(or accept) secure connection?
If your not running behind a proxy, it's not required. Eg, if your running multiple websites on a server, chances are your using a Proxy.
X-Forwarded-For header attributes get added when doing this so that your proxy can see what the original url was, proxying in the end will be going to localhost you see. The reason why it's needed is that X-Forwared-For can be faked, there is nothing stopping the client adding these too, not just a proxy. So trust-proxy should only be enabled on the receiving end, that would be behind your firewall. Because you have control, you can trust this.
So in a nutshell, if your website is running behind a proxy, you can enable it. If you website is running direct on port 80, you don't want to trust it. As the sender could pretend to be coming from localhost etc.
I have a web app that allows people to generate a list of songs by artists that are related to a particular artist. I want to be able to connect to the user's Spotify account and create a playlist for them from that list of songs, but I need to get an access token. I have a developer account and client ID and am trying to work through the Authorization Flow, but it's not working for me. Instead, I get this error: XMLHttpRequest cannot load https://accounts.spotify.com/authorize/?client_id=d137fe25b31c4f3ba9e29d85f…:3000/callback&scope=user-read-private%20user-read-email&state=34fFs29kd09. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
This is a portion of my scripts.js file (i'm using the spotify-web-api-js node module):
$('#spotify').on('click', function() {
$.support.cors = true;
$.getJSON("https://accounts.spotify.com/authorize/?client_id=d137fe25b31c4f3ba9e29d85f4e47c66&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fcallback&scope=user-read-private%20user-read-email&state=34fFs29kd09", function(json2){
$.getJSON("https://accounts.spotify.com/api/token/?grant_type=authorization_code&code=" + json2.code + "&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fcallback&client_id=d137fe25b31c4f3ba9e29d85f4e47c66&client_secret={...}", function(json3) {
s.setAccessToken(json3.access_token);
});
});
});
});
According to my research, it's a CORS-related issue. I'm making edits to my ExpressJS server to remedy this cross-origin problem and installed the cors node module, but I'm still getting the same error.
index.js server:
var express = require('express');
var cors = require('cors');
var app = express();
var port = 3000;
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.use(express.static(__dirname + '/public')); // looks in public directory, not root directory (protects files)
app.get('/', function(req, res) {
res.send(__dirname + '\\index.html')
});
app.listen(port, function() {
console.log('CORS-enabled web server listening on port ' + port);
});
When I go to the URL in question directly through my browser, it gives me the expected "Do you authorize this app to use your Spotify information" form.
Should I require 'cors' in 'scripts.js' for it to work? Does anyone have any other suggestions?
I believe the issue here is that you're attempting to retrieve JSON data from the endpoint where you should direct your users. So instead of making a request to it, you should supply a button on your page that links to your https://accounts.spotify.com/authorize/{...} URL. The user will proceed to give your application the permissions you've requested as specified in the scope parameter, and will be directed back to the URL you've specified in the redirect_uri parameter. This is where you get the authorization code, which you can use in the https://accounts.spotify.com/api/token/{...} endpoint. Read more about the Authorization Code flow in the Authorization Guide.
Spotify Web API support three different oAuth flows, and you might be interested in Implicit Grant. Examples of all of these flows written in Javascript using Node is available at https://github.com/spotify/web-api-auth-examples.
I was wondering how can I create a https server in node listening on Port 443 in a way that when I type :
https://my.ip.address:443 it should work.
https://my.ip.address it should work.
my.ip.address (without the https://) it should work and redirect me to https)
my.ip.address:443 it should work and redirect me to https
So far I was only able to make the first and second url work.
So my question is how can I make it also work for the other two possibilities (the final two). Thanks
If you type my.ip.address into a browser's address bar then it will request http://my.ip.address:80. To get that to work with your SSL version you need to:
Listen for HTTP (not HTTPS) on port 80
Issue a 301 HTTP Redirect to the SSL site
If you type my.ip.address:443 into a browser, then it will request http://my.ip.address:443. This will try to make an HTTP request without setting up SSL first and get an error. There is nothing you can do about that.
You can make redirects from http to https.
Via nginx
https://github.com/vodolaz095/hunt/blob/master/examples/serverConfigsExamples/nginx.conf#L22-L39
server {
listen 80;
server_name example.org;
rewrite ^ https://$host$request_uri? permanent;
}
Via expressjs middleware
https://github.com/vodolaz095/hunt/blob/master/examples/index.js#L133-L139
something like this:
app.use(function (request, response, next) {
if (request.protocol === 'http') {
response.redirect('https://yourhostname.com' + request.originalUrl);
} else {
next();
}
});
I currently have a HTTPS web server listening on port 443 on my host machine.
My goal is to set up another HTTPS web server on the same host machine, change ports on both web servers, and then set up a proxy server using node-http-proxy listening on port 443 instead. The proxy server then delegates requests based on custom logic to the servers on other ports.
Below is the proxy server I adapted from one I successfully use when proxying plain HTTP requests on port 80. However, when I try to run this code the browser displays the message 'Secure Proxy Server unable to handle your request at this time.' and console logs '[Error: UNABLE_TO_VERIFY_LEAF_SIGNATURE]' It does make it to the point where it tries to proxy the request to the server listening on a different port.
var sugar = require('sugar')
var url = require('url')
var https = require('https')
var httpProxy = require('http-proxy')
var fs = require('fs')
//configure proxy
var ssl proxy = httpProxy.createProxyServer({
ssl: {
key: fs.readFileSync('/cert/server.key', 'utf-8'),
cert: fs.readFileSync('/cert/mydomain.crt', 'utf-8')
}
})
sslproxy.on(
'error',
function(err, req, res) {
console.log(err)
res.end('Secure Proxy Server unable to handle your request at this time.')
}
)
//configure and start server that uses proxy
var credentials = {
key: fs.readFileSync('/cert/server.key','utf-8'),
cert: fs.readFileSync('/cert/mydomain.crt', 'utf-8')
}
var sslserver = https.createServer(
credentials,
function(req, res) {
console.log("Received request on secure proxy server")
var target = url.parse(req.url)
if(target.pathname.startsWith('/version1')) {
console.log("Forwarding request to port 444")
sslproxy.web(req, res, {target: 'https://localhost:444'})
} else {
console.log("Forwarding request to 445")
sslproxy.web(req, res, {target: 'https://localhost:445'})
}
}
)
sslserver.listen(443)
Couple thoughts:
I tried using node-ssl-root-cas as indicated in the answer to another question, but nothing appeared to change. My SSL certificate is from Network Solutions.
The targets for my proxy are localhost:444 and localhost:445 because those ports are not open externally and cannot be. Not sure if the localhost in the host name is affecting the https proxy.
Try this: process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
And look at this:
// AUTHENTICATION MODES
//
// There are several levels of authentication that TLS/SSL supports.
// Read more about this in "man SSL_set_verify".
//
// 1. The server sends a certificate to the client but does not request a
// cert from the client. This is common for most HTTPS servers. The browser
// can verify the identity of the server, but the server does not know who
// the client is. Authenticating the client is usually done over HTTP using
// login boxes and cookies and stuff.
//
// 2. The server sends a cert to the client and requests that the client
// also send it a cert. The client knows who the server is and the server is
// requesting the client also identify themselves. There are several
// outcomes:
//
// A) verifyError returns null meaning the client's certificate is signed
// by one of the server's CAs. The server know's the client idenity now
// and the client is authorized.
//
// B) For some reason the client's certificate is not acceptable -
// verifyError returns a string indicating the problem. The server can
// either (i) reject the client or (ii) allow the client to connect as an
// unauthorized connection.
//
// The mode is controlled by two boolean variables.
//
// requestCert
// If true the server requests a certificate from client connections. For
// the common HTTPS case, users will want this to be false, which is what
// it defaults to.
//
// rejectUnauthorized
// If true clients whose certificates are invalid for any reason will not
// be allowed to make connections. If false, they will simply be marked as
// unauthorized but secure communication will continue. By default this is
// false.
//
Both, solution and additional infos, are from here: Node.js HTTPS 400 Error - 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'