Multiple subdomains connected to meteor app - javascript

Many subdomains are forwarded to subdomain X where my meteor app is working.
I'm using code which doesn't work:
WebApp.connectHandlers.use(function(req, res, next) {
console.log(req.connection.domain); // is null
console.log(req.server.domain); // is null
next();
});
Trying also to use IronRouter on server:
Router.map(function () {
this.route('testRoute', {
where: 'server',
path: '*',
action: function () {
console.log(this.request.connection.domain); // null
}
});
});
I know that FastRender injects headers and it works , but the question is :
How can I get subdomain from which user accesses meteor app using WebApp.connectHandlers or IronRouter ?

In the first example, log req.headers to console as well. One of the strings there should contain the original request domain. However, that might depend on how your proxy is configured.

Related

Next.js redirect from an API route

I am building a back-office app that requires users to sign in.
I have 2 external APIs:
API A : to manage user accounts and sessions
API B : to perform CRUD actions on another database (unrelated to users database)
The problem is that I don't want users to be able to perform calls to API B if their session is not valid. So I added some API endpoints in Next (under pages/api) that do the following actions:
verifying the validity of the session against API A
if session is valid: continue to step 3, if not: redirect to page /login
make the call to API B
Everything works fine if the session is valid but it fails if the session is not valid.
I have tried
res.redirect(307, '/login').end()
and
res.writeHead(307, { Location: '/login' }).end()
but it didn't work. It fails even by specifying the whole path (http://localhost:3000/login). What I don't understand is that I am successfully redirected to my /login page if I make the request directly from the browser (GET http://localhost:3000/api/data). It doesn't work when I make the request with Axios inside a React component.
Any idea how I can fix this?
As #juliomalves and #yqlim explained, I had to make the redirect manually based on the response of the API.
Faced same problem solve using below code:
Api
res.status(200).json({ success: "success" }) //add at last of the api to give response
page
import Router from 'next/router'
let res = await fetch('api', {
method: 'POST', // or 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
if (res.status == 200) {
Router.push('/location')
}
Answer is correct as #Jules Grenier sayes,but provided an example
You do not need .end(). Have you tried res.redirect(307, '/login')?
In Next.js v12 and v13, the following works for me.
// /api/example.js
const handler = async function (req, res) {
// custom logic
if (failed)
return res.redirect(307, '/login')
}
export default handler;
The API request must be initiated by a <form>.
redirect will not work with <fetch>

Sapper session not setting properly in production build without page reload

I'm working on a project using Sapper, and been struggling with something for a bit now – can't quite figure it out. I'm using Polka for my server (it was included with the sveltejs/sapper-template#rollup template so I went with it), and cookie-session for my session middleware.
Here is my Polka configuration, where I seed session data also:
polka()
.use(
compression({ threshold: 0 }),
sirv('static', { dev }),
cookieSession({
name: 'session',
keys: [
'6e818055-d346-4fcb-bf56-4c7d54cb04ab',
'60f3e980-6e9c-460d-8ea7-af1fffbdb92f'
]
}),
sapper.middleware({
session: (req, res) => ({
user: req.session.user
})
})
)
.listen(PORT, err => {
if (err) console.log('error', err);
});
When a user logs in, it's handled in routes/login.js essentially some profile info and tokens get set on session.user and the request is redirected back to the root path. I'm using #polka/send-type to respond. See below:
req.session.user = {
accessToken: access_token,
name: first_name,
pic: picture.data.url
};
send(res, 302, '', {
Location: appUrl
});
There, I have a preload module for routes/index.svelte checks if session.user exists, and if so redirects to dashboard:
<script context="module">
export async function preload(page, session) {
const { user } = session;
if (user) {
return this.redirect(302, "dashboard");
}
}
</script>
This all works fine in dev, but when I npm run build and build for production it doesn't so well. It seems like the session.user isn't getting populated after the redirect in login.js.
The session object that I get in preload doesn't have session.user set after login, and vice versa on logout where session.user is simply set to null and the client is redirected to the root, session.user is still populated.
If I refresh the browser, session.user is in the correct state. Without a refresh – if I just logged out I can click around as if I were logged in, and if I had just logged in nothing happens as session.user is undefined.
Just not sure why it'd work on the dev build but not in production. Given that the session.user state is correct on browser refresh, I'm guessing it's not an issue with the cookie middleware configuration. Seems like I'm missing something else. Any help would be hugely appreciated!
Sapper does indeed handle the cache headers differently for dev and production environment. That's why you are experiencing it this way.
But there is a simple solution by changing the sapper.middleware function:
sapper.middleware({
session: (req, res) => {
res.setHeader('cache-control', 'no-cache, no-store')
return { user: req.session.user }
}
})
This sets the cache-control as you want it.

Nodejs - API and application on the same server issue

I have a server, which holds my API and my application.
/ - returns my application
/api - every request starts with that pre word api, e.g. /api/users and so on.
My issue: When I enter my app not by directly example.com, but e.g. example.com/users or even some random word, like example.com/stackOverflow it returns API response!! My app does not even start, the response is like Cannot GET /stackOverflow
I guess it's because it's on one, single server... Is there a way to fix it somehow in node?
var app = expres();
app.get("/api/users", function (req, res) {
getUsers(function (err, users) {
if (err) {
return res.status(500).send('Error');
}
return res.json(users);
});
});
app.get("/api/user/:_id", function (req, res) {
getUserById(req.params._id, function (err, user) {
if (err) {
return res.status(500).send('Error');
}
return res.json(user);
});
});
You could create different subdomains instead of using the same domain just changing URI.
Then with reverse proxy configuration on nginx/apache you could redirect the requests to different server ports. That way you could have your application running on port 80 and your NodeJS API on port 3000 let's say.
Example:
APP.domain.com redirects to localhost:80
API.domain.com redirects to localhost:3000
I hope I made myself clear.
You could also do that with the structure you already have not needing to run them on different ports.
Here is some documentation regarding how to configure that on nginx:
https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/

Protect API routes in Node.js

I have some routes in my Node.js API sending data from a MongoDB database to an Angular 4 frontend.
Example:
Node.js route:
router.get('/api/articles', (req, res) => {
Article.find({}, (err, articles) => {
if(err) return res.status(500).send("Something went wrong");
res.status(200).send(articles);
});
});
Angular 4 service function:
getArticles() {
return this.http.get('http://localhost:3000/api/articles')
.map(res => res.json()).subscribe(res => this.articles = res);
}
The question is, how do I protect my Node.js API routes from browser access? When I go to http://localhost:3000/api/articles I can see all my articles in json format.
This is not a security measure, just a way to filter the request. For security use other mechanisms like JWT or similar.
If the angular app is controlled by you then send a special header like X-Requested-With:XMLHttpRequest (chrome sends it by default for AJAX calls) and before responding check for the presence of this header.
If you are really particular about exposing the endpoint to a special case use a unique header may be X-Request-App: MyNgApp and filter for it.
You can't really unless you are willing to implement some sort of authentication — i.e your angular user will need to sign into the api.
You can make it less convenient. For example, simply switching your route to accept POST request instead of GET requests will stop browsers from seeing it easily. It will still be visible in dev tool or curl.
Alternatively you can set a header with your angular request that you look for in your express handler, but that seems like a lot of work for only the appearance of security.
Best method is to implement an authentication token system. You can start with a static token(Later you can implement dynamic token with authorisation).
Token is just a string to ensure the request is authenticated.
Node.js route:
router.get('/api/articles', (req, res) => {
let token = url.parse(req.url,true).query.token; //Parse GET param from URL
if("mytoken" == token){ // Validate Token
Article.find({}, (err, articles) => {
if(err) return res.status(500).send("Something went wrong");
res.status(200).send(articles);
});
}else {
res.status(401).send("Error:Invalid Token"); //Send Error message
}
});
Angular 4 service function:
getArticles() {
return this.http.get('http://localhost:3000/api/articles?token=mytoken') // Add token when making call
.map(res => res.json()).subscribe(res => this.articles = res);
}
With Express, you can use route handlers to allow or deny access to your endpoints. This method is used by Passport authentication middleware (which you can use for this, by the way).
function isAccessGranted (req, res, next) {
// Here your authorization logic (jwt, OAuth, custom connection logic...)
if (!isGranted) return res.status(401).end()
next()
}
router.get('/api/articles', isAccessGranted, (req, res) => {
//...
})
Or make it more generic for all your routes:
app.use('*', isAccessGranted)

Node and Angular cookie path

I'm working on a login/out functionality for my web application. When the user logged in my NodeJS(Express) server sets cookies variable called "user" on .mydomain.com with path '/'. Then I use AngularJS to access user cookies. It reads it fine from any page under my domain, but when I want to log the user out. I try deleting the cookies value, but it doesn't delete it on any other pages than the index page ('/').
I know there's something to do with the cookies path, but as far as I know it's ok to read/write cookies with path '/' form anywhere in the same domain. Is that not the case?
Setting the cookies, NodeJS
res.cookie('user', JSON.stringify(response.user), {
expires: moment().add('d', 2).toDate(),
path: '/',
domain: '.mydomain.com'
});
Deleting the cookies from /myPage/page2, AngularJS
delete $cookies['user'];
Is there anyway this could work?
Thanks!
I usually post to the server.
So, on the client side, I have something like:
$scope.logout = function() {
$http.post('/logout').then(function(){
$state.go('login');
});
};
and on the server side:
app.post('/logout', function(req, res, next) {
delete req.session.user
req.session.regenerate(done);
res.json(200, 'OK');
});

Categories