Dynamic requires in nodejs before module.exports - node.js

I have an app I'm working on that has active directory login and local login. When checking for permissions I want to allow permissions to either be set by AD group membership, or if not using AD then locally stored permissions in the database. As a result I have 2 different modules to handle permission checks. Is there a way to have a require at the top, before module.exports to be done dynamically through an if statement or something similar? I thought I could assign a process.env.isLocal and process from there but it doesn't seem to work I get an error that says Permissions is not defined
const moment = require('moment');
const AdminPortal = require('../models/adminportal');
if(process.env.isLocal) {
const Permissions = require('../models/localLogin/localPermissions');
} else {
const Permissions = require('../models/permissions');
}
const isAuthenticated = require("../config/middleware/isAuthenticated");
const config = require("../config/configFile.js").get(process.env.NODE_ENV.trim());
module.exports = function(app){
I suppose maybe I need to have both code sets in one file and then choose which one to use based on if its a local login or not, I was just hoping to keep them separated.

Your issue with the Permissions variable is that it's block scoped so it's only available inside the block in which you declare it. So, this:
if(process.env.isLocal) {
const Permissions = require('../models/localLogin/localPermissions');
} else {
const Permissions = require('../models/permissions');
}
Creates a Permissions variable that is only usable within the if/else block. If you want it to be available at a higher scope and use the same if/else construct, then you have to declare the variable at that higher scope which means you can't use const:
let Permissions;
if(process.env.isLocal) {
Permissions = require('../models/localLogin/localPermissions');
} else {
Permissions = require('../models/permissions');
}
// you can use Permissions here
FYI, this is a place where the ternary operator can be useful:
const Permissions = process.env.isLocal ?
require('../models/localLogin/localPermissions') :
require('../models/permissions');

Related

how do i use bot.on features inside a module.exports file

I developed an algorithm that when u type in discord server's text channel : "-nuke #tag" that member will get a "Muted" role and his id will be added to an array. If he leaves the server and joins back, the bot will compare the new member's id with all the ids in the array and if they are matching it will automatically give that person the "Muted" role. The problem is, the bot.on doesn't seem to work inside something else than index.js. I dont really want to go inside all the event handlers and stuff, just to get this one working nuke.js
This answer is in reference to a comment I made. This will show you how to create and access a global map.
To start you need to extend the client class by the map you want to use. You do that like this.
const { Client } = require('discord.js');
module.exports = class extends Client {
constructor(config) {
super({});
this.muteIDs = new Map(); // you can name it whatever you like
this.config = config;
}
};
You should do that in a separate file. Lets call that file clientextend.js. Now you can create your bot client like you usually would, however you need to require the file that you just created. This example has both the file in which you extend the client and the file you create the client in, in the same directory. Note: In your example you have bot instead of client.
const Client = require('./clientextend.js')
const client = new Client();
You now have access to the map you created anywhere you have your client available to you. You can access it like this.
muteIDs = client.muteIDs;

Copy object from one node to another in Cloud Functions for Firebase

I'm using Cloud Functions for Firebase, and I'm stuck with what seems to be a very basic operation.
If someone adds a post, he writes to /posts/. I want a portion of that post to be saved under a different node, called public-posts or private-posts, using the same key as was used in the initial post.
My code looks like this
const functions = require('firebase-functions');
exports.copyPost = functions.database
.ref('/posts/{pushId}')
.onWrite(event => {
const post = event.data.val();
const smallPost = (({ name, descr }) => ({ name, descr }))(post);
if (post.isPublic) {
return functions.database.ref('/public-posts/' + event.params.pushId)
.set(smallPost);
} else {
return functions.database.ref('/private-posts/' + event.params.pushId)
.set(smallPost);
}
})
The error message I get is: functions.database.ref(...).set is not a function.
What am I doing wrong?
If you want to make changes to the database in a database trigger, you either have to use the Admin SDK, or find a reference to the relevant node using the reference you've been given in the event. (You can't use functions.database to find a reference - that's used for registering triggers).
The easiest thing is probably to use event.data.ref (doc) to find a reference to the location you want to write:
const root = event.data.ref.root
const pubPost = root.child('public-posts')

Get Owner(s) in .NET Azure Active Directory groups

I have an email account which is a Security Group where there are few members in it. I am trying to figure out the email address of the owner of the group but I haven't been able to figure it out.
Below is the source code
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(serviceRoot, async () => await Task.FromResult(accessToken));
var group = (Group)await activeDirectoryClient.Groups.Where(u => u.Mail == "email#domaincom").ExecuteSingleAsync();.
var groupFetcher = activeDirectoryClient.Groups.GetByObjectId(group.ObjectId);
var membersResult = groupFetcher.Members.ExecuteAsync().Result;
var ownerResult = groupFetcher.Owners.ExecuteAsync().Result;
After I execute this code, I can see the members of the Group but why ownerResult variable is always empty? How can I retrieve the owner of the group?
I am testing using the code below(Microsoft.Azure.ActiveDirectory.GraphClient with version 2.1.1)and it works well for me. Please ensure that the group have the owners assigned.
var group = (Group) client.Groups.Where(u => u.Mail == "email#domain.onmicrosoft.com").ExecuteSingleAsync().Result;
var groupFetcher = client.Groups.GetByObjectId(group.ObjectId);
//var membersResult = groupFetcher.Members.ExecuteAsync().Result;
var ownerResult = groupFetcher.Owners.ExecuteAsync().Result;
foreach (var owner in ownerResult.CurrentPage)
Console.WriteLine(((Microsoft.Azure.ActiveDirectory.GraphClient.User)owner).DisplayName);
You can check it from Azure portal like figure below:
If the owner exists, I also suggest that you capture the request using Fiddler to check whether the response is expected.

Change connection used on runtime

I hope you can help me (us). I'm working on a API project which have two databases :
Production DB : api.myapp.fr
Testing DB : test.api.myapp.fr
Theses two databases are writable by the user.
When a user call our API, he can set the authorization header whichever he needs. For example :
Authorization: s_0
Will perform operations on api.myapp.fr and
Authorization: s_t_0
Will perform operations on test.api.myapp.fr .
My question is : How can I do that with sails ?
Actually, I have a policie which check if the user is using a production key or a testing key, and I override the default models with the one for testings purposes, like this :
if (!is_production) {
req.session.isProd = false;
req.session.logs.environment = "test";
User = UserTest;
Payment = PaymentTest;
PayzenStatus = PayzenStatusTest;
Transaction = TransactionTest;
Card = CardTest;
Doc = DocTest;
}
But you can see the problem if a user makes a test request and then a production request, the models are still the tests ones...
I use my models in services and policies, therefor I can't do
req.models = {};
// If not in production, use the test models
if (!is_production) {
req.session.isProd = false;
req.session.logs.environment = "test";
req.models.User = UserTest;
req.models.Payment = PaymentTest;
req.models.PayzenStatus = PayzenStatusTest;
req.models.Transaction = TransactionTest;
req.models.Card = CardTest;
req.models.Doc = DocTest;
}
// Otherwise use the production models
else {
req.models.User = User;
req.models.Payment = Payment;
req.models.PayzenStatus = PayzenStatus;
req.models.Transaction = Transaction;
req.models.Card = Card;
req.models.Doc = Doc;
}
If you have any idea on how ton achieve this (whatever the way, we can still perform deep changes in our code), I would be really happy to ear it.
Thanks
Two different ways of doing this.
First you could set an environment variable on your production host and check that environment variable to see if you are running in prod. If you are running in prod then use the URI to the production database.
Secodonly, which is probably the better way of doing this creating a config.js file that allows you to read environment variables. What I do for all my apps is set environment variables for connection info to databases and API keys. When running locally/testing I have some defaults in my app but when they environment variables are set they are read and used. So set the environment variable in production to point to your production databases.
The config.js file Im posting below contains references to VCAP, which assumes you are running on Cloud Foundry.
config.js
var VCAP_SERVICES = process.env["VCAP_SERVICES"],
vcapServices;
if (VCAP_SERVICES) {
vcapServices = JSON.parse(VCAP_SERVICES);
}
function getEnv(propName, defaultValue) {
if (process.env[propName]) {
return process.env[propName];
} else {
return defaultValue;
}
}
module.exports = function() {
return {
getEnv : getEnv,
couchDbURL: function() {
// Default to a local couch installation for development
if (VCAP_SERVICES) {
return vcapServices["cloudantNoSQLDB"][0].credentials.url;
}
else {
return "http://localhost:5984";
}
},
couchDbName: function() {
return getEnv("COUCHDB_NAME", "mydb");
}
};
};
app.js
var config = require("./config")();
console.log(config.couchDbURL());

How to Deactivate a LDAP User?

I am using a library to authenticate LDAP Users, whose code is as follows:
public void authUser(String username, String pwd)
throws Exception
{
try
{
Properties env = getEnvironmentForContext();
env.put("java.naming.security.principal", "uid=" +
username + ",ou=users, dc=company"));
env.put("java.naming.security.credentials", pwd);
context = getContext(env);
System.out.println("Authentication Succeeded");
}
catch (Exception e)
{
System.out.println("Authentication Failed");
throw e;
}
}
Please note, i cannot modify the above Authentication Code. It comes from a external Library.
But, i want to deactivate some users (not delete them), so that Authentication Fails.
I am using LDAP (not Active Directory). Do not know what LDAP Software it is though, i can connect to it using 'LDAP Browser Client'.
The users exist under: dc=company, ou=users, uid=username
What attribute can i add/change on LDAP 'user' to de-activate a user.
Could i move the user to a different group like: dc=company, ou=deactivatedusers, uid=username? But this is not the preferred option, plus am not sure best way to do that.
EDIT: The LDAP being used is: Netscape/Sun/iPlanet
To answer your question per the Oracle iPlanet (Sun) documentation :
Setting the attribute nsAccountLock to true will disable a users account, and prevent them from binding to the directory.
However, in terms of the code you already have, I just don't see any way of accomplishing this... Is there something preventing you from writing your own implementation for iPlanet using the System.DirectoryServices.Protocols namespace in .Net?
Here is how I bind and authorize users against an iPlanet server :
//Build servername from variables
var BuildServerName = new StringBuilder();
BuildServerName.Append(ServerName);
BuildServerName.Append(":" + Convert.ToString(Port));
var ldapConnection = new LdapConnection(BuildServerName.ToString());
//Authenticate the Admin username and password, making sure it's a valid login
try
{
//Pass in the network (administrative) creds, and the domain.
var networkCredential = new NetworkCredential(Username, Password, config.LdapAuth.LdapDomain);
ldapConnection.SessionOptions.SecureSocketLayer = true;
ldapConnection.SessionOptions.VerifyServerCertificate += delegate { return true; };
ldapConnection.AuthType = AuthType.Anonymous;;
ldapConnection.Bind(networkCredential);
//Lets find this person so we can use the correct DN syntax when we authorize them.
SearchRequest FindThem = new SearchRequest();
FindThem.Filter = config.LdapAuth.LdapFilter.Replace("{{Patron}}", Patron);
FindThem.DistinguishedName = config.LdapAuth.LdapDomain;
FindThem.Scope = System.DirectoryServices.Protocols.SearchScope.Subtree;
//We'll execute a search using the bound user
SearchResponse searchresults = (SearchResponse) ldapConnection.SendRequest(FindThem);
//Should only get on result back, if not throw an error
if(searchresults.Entries.Count == 1)
{
SearchResultEntryCollection entries = searchresults.Entries;
SearchResultEntry thispatron = entries[0];
PatronDN = thispatron.DistinguishedName;
}
}
If you wanted to move disabled users to a specific group, from this point you could write logic to check the DistinguishedName of that user, and throw a handled exception if their DistinguishedName contains the name of that group. Also, if the nsAccountLock attribute is available to your binding account as a readable attribute, you could just check the value of that attribute for true, and handle the user accordingly.
Here is the java code for disabling and enabling user in Active Directory using JNDI.
Make sure to connect with your AD before calling below code.
public void disableEnableUser() throws Exception {
ModificationItem[] mods = new ModificationItem[1];
//To enable user
//int UF_ACCOUNT_ENABLE = 0x0001;
//mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("userAccountControl",Integer.toString(UF_ACCOUNT_ENABLE)));
// To disable user
int UF_ACCOUNT_DISABLE = 0x0002;
mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("userAccountControl",Integer.toString(UF_ACCOUNT_DISABLE)));
ctx.modifyAttributes("CN=John ABC,OU=Users,OU=anyone,DC=yourcompanyname,DC=com", mods);
}
Distinguished name = "CN=John ABC,OU=Users,OU=anyone,DC=yourcompanyname,DC=com"
This name is depend on your structure of Active Directory, you can confirm from your suport team.
If the directory software supports a password policy feature, it probably provides attributes to lock/deactivate the user. If not, you can simply nullify the password attribute (e.g., userpassword). The LDAP server should return the "inappropriate authentication" error to the client when the authenticated bind is performed.
You could just change the user's password. If it's OpenLDAP with the password-policy overlay, or another LDAP server that supports locking, you can lock the user as well. You really will have to find out.

Resources