How do limiting access through a iron-router in meteor app? - mongodb

i have routing file which lock like:
Router.map(function(){
this.route('gameSmall', {path: '/'});
this.route('gameMedium', {path: '/game-medium'});
this.route('gameLarge', {path: '/game-large'});
});
etc.
if i want to limiting access to some of path (only for some user who has password), can i configure it in router file? or only through native js in template?

Iron Router does not support limiting access by a configuration file. Instead you define access in your js source.
You can limit access to routes globally and per route. Both use the onBeforeAction event to evaluate access to the route(s).
onBeforeAction accepts a callback function where you write your access rule.
A global onBeforeAction event might look something like this:
Router.onBeforeAction(function() {
if (!Meteor.isServer) {
// Check the user. Whether logged in, but you could check user's roles as well.
if (!Meteor.userId()) {
this.render('pageNotFound'); // Current route cancelled -> render another page
} else {
this.next(); // Continue with the route -> will render the requested page
}
}
},
{
except: ['gameSmall']
});
Notice the except field in the second parameter. It contains an array of routes to be excluded from the onBeforeAction and therefore these are always rendered. There is also a field only which does the opposite, include routes to be evaluated by the onBeforeAction.
Also note that I used a template pageNotFound (404 page). You can define that page in IR's configuration like this:
Router.configure({
notFoundTemplate: 'pageNotFound'
});

Related

PWA multiple virtual paths with same backend code does not create separate installs

I have a generic common NodeJS app that multiple users access. The users are identified via the path. For example: https://someapp.web.app/abc can be one path while https://someapp.web.app/def can be another path.
On the NodeJS server path, I send the same server code by passing the path parameters to the program. The route appears something like this:
app.get('/*', async (req, res) => {
...
locals.path = req.path;
...
res.render('index', locals);
}
In the above index is a template that uses locals data for customisation
What I would like is that for each path there is a separate manifest and its associated icons and that on a single device (phone or desktop) multiple installations be possible. Thus, https://someapp.web.app/abc be one icon and https://someapp.web.app/def be another icon.
I am having difficulty in the placement and the scoping of the manifest and service worker. It always adds only one icon (the first path installed) to the home screen or desktop. My settings are:
In the public (root) folder I have each manifest viz. abc-manifest.json and def-manifest.json and a common sw.js.
The abc-manifest.json is:
'scope': '/abc',
'start_url': '/abc',
...
The access to the service-worker from the index.js is:
if (navigator.serviceWorker) {
navigator.serviceWorker.register('sw.js')
.then(function (registration) {
console.log('ServiceWorker registration succeeded');
}).catch(function (error) {
console.log('ServiceWorker registration failed:', error);
});
}
I have tried changing the paths of scope and start_url to / but it did not work. Since all requests to the public path are common and not within the virtual /abc path, I am unable to figure out how to get this working.
Thanks
Could that be an option to have a dedicated route that will redirect the user to /abc or /def?
In the manifest:
{
"start_url": "https://example.com/login",
"scope": "https://example.com/",
}
/login would make sure to redirect to /abc or /def.
This way you could keep one service worker, and one manifest.
And in the Service Worker, maybe try to return the specific icon based on file name.
self.addEventListener('fetch', e => {
// Serve correct icon
let url = new URL(e.request.url)
if (url.pathname.contains('/android-icon-512.png')) {
return respondWith(e, '/android-icon-512-abc.png')
}
// other ifs…
// Return from cache or fallback to network.
respondWith(e, e.request)
})
const respondWith = (e, url) =>
e.respondWith(caches.match(url)
.then(response => response || fetch(e.request).then(response => response))
)
Maybe you’ll need a specific header to do this, or use a URL parameter (icon.png?user=abc) to help query the right icon. I’m throwing idea, because it probably depends a lot on your app back-end and/or front-end architecture.
I once did this: the back-end (PHP / Laravel) handled the correct returning of the icon and manifest (I had one for each use case) based on other stuff.

Show a popup on redirect from old to new domain

I need to show a popup when the old domain is redirected to new domain in the nuxt js.
I have modified the . htaccess file and have a modal in the index.vue.
mounted() {
const modal = document.getElementById('modal')
if (document.referrer.indexOf('https://olddomain.com') > -1) {
alert('Previous domain redirected')
modal.style.display = 'block'
}
}
But there is no popup displayed. Is there a better way to do this using nuxt.
You can try the following:
Create a middleware in middleware/popupCheck.js name is up to you..
when you are creating middleware in Nuxt you should export default function, like this:
export default function(context) {
if (context.req.headers['your-custom-header']) {
// Use vuex store to dispatch an action to show a popup or set a cookie
// to listen to. Here the logic should be defined by the implementation.
}
}
The point here is to listen for a header in the request, could be a cookie also, that you have to send from your old site for every request, so make sure it's not something generic, but instead something that you cannot hit easily by mistake..
After you create your middleware you can use it on pages or layouts views, and you should add it in the default object you export:
export default {
middleware: 'popupCheck',
}
Without importing the middleware you just call it by name, this could also be an array if you wish to add multiple middlewares, and the order in that array is important.
There might be a better way to solve this, but this is the first one that came to my mind..

Sails js ignore id in create/update requests

Sails enables passing an id property when creating an entity,
i want to ignore the id value the user sent and just set my own with autoincrement
how can i do this?
You can do this per model in sails lifecycle callbacks. For example, if you have a User model, in models/User.js you can add:
module.exports = {
attributes: {
// etc
},
beforeCreate: function(attribs, cb) {
// modify the attributes as needed here
delete attribs.id;
cb();
}
}
There are similar callbacks for beforeUpdate, etc. Unfortunately, this would have to be done in every model you want to affect.
One way to remove ids from every blueprint create request would be to use a policy. Create a policy that strips id from req.body, then apply that policy to the route POST /:model (there's an example of applying policies directly to routes here). If you do this, be careful as this could mask other POST routes you are trying to use.

Meteor FlowRouter: replace path in history for restricted route

I'm using FlowRouter in a Meteor app. In one case, a resource is not available until a certain date/time, so we redirect to another route. Is there anyway to replace the route to the restricted resource with the path to the redirect such that the restricted resource route will not appear in the browser history. Doing will make the history (using back, forward) more UX friendly.
I can achieve this in FlowRouter's triggersEnter for the route, by stepping outside of FlowRouter with something like:
if(restricted) {
return window.location.replace(`/waitingroom/${resourceId}/user/${Meteor.userId()}`);
}
...but this causes a page reload, which is sort of undesirable.
Any idears?
Functions pass to triggersEnter have the 2nd param named redirect you can use it to redirect to other pages without reloading the page and having a clean history:
FR.route('/restricted-route', {
name: 'RestrictedRoute',
triggersEnter: [function(context, redirect) {
redirect('/replace-route');
}]
});
FR.route('/replace-route', {
name: 'ReplaceRoute',
action() {
// ...
}
});
Updated
I am not sure why it's required to be sync. Anyway FlowRouter uses Page.js behind the scene to do navigation, if you can not use redirect then this should work:
FR.route('/restricted-route', {
name: 'RestrictedRoute',
triggersEnter: [function(context, redirect) {
Meteor.setTimeout(() => {
FlowRouter._page.replace('/replace-route');
}, 1000);
}]
});
Note: this is not the public API, therefore you should test it carefully before using in production.

How can I show a maintenance page?

I'd like to show a maintenance page on my site. I plan on saving a Boolean value to the db in order to control when to show the page or not. How can I have the maintenance page show for just my controller routes? I'd like to continue to have sails serve scripts, stylesheets, and images normally.
You could use a policy to achieve this.
// api/policies/inMaintenance.js
module.exports = function(req, res, next) {
var maintenanceMode = ... // get the value
if (maintenanceMode) return res.view('maintenance');
next();
}
// config/policies.js
module.exports.policies = {
'*': 'inMaintenance',
...
}
In your views folder add maintenance.ejs.
All the assets will still be available.
There is one drawback to this approach though, if in config/routes.js you have a route pointing directly to a view it will not go through the policy. Thus, you need all routes to be handled by controllers.
You can check the Sails documentation on policies to better understand how they work.