How to get Cognito Identity Pool ID for a new user - javascript

After importing the AWS module I go ahead and declare the cognitoidentityserviceprovider variable:
let AWS = require("aws-sdk");
let AWS_REGION = "us-east-1";
let USER_POOL_ID = 'us-east-1_4RQvUuPkX';
let AWS_COGNITO_CLIENT_ID = 'l703om838lkem323m04tiparls';
let AWS_COGNITO_IDENTITY_POOL_ID = 'us-east-1:112e122-bdd5-1234-983b-0afff8de2b3f';
AWS.config.update({
region: AWS_REGION,
});
let cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider({
apiVersion: "2016-04-19",
region: AWS_REGION
});
After the initial configuration is set I am ready to define the create_user function that I can use to create a new Cognito user supplying this functions with the user's email and password:
async function create_user(email, password) {
let params = {
UserPoolId: USER_POOL_ID,
Username: email,
DesiredDeliveryMediums: ["EMAIL"],
TemporaryPassword: password,
UserAttributes: [
{
Name: "email",
Value: email
},
{
Name: "email_verified",
Value: "true"
}
]
};
return await cognitoidentityserviceprovider.adminCreateUser(params).promise();
}
Next, I define another function confirm_user which I am going to use to confirm the new user by setting the user's password:
async function confirm_user(sub_id, password) {
let params = {
Password: password,
UserPoolId: USER_POOL_ID,
Username: sub_id,
Permanent: true
};
return await cognitoidentityserviceprovider.adminSetUserPassword(params).promise();
}
With both create_user and confirm_user functions defined I can now create a new Cognito user and confirm it on spot without a need for the user to confirm the sign-up process:
async function main(email, password) {
let user_data = await create_user(email, password);
let sub_id = user_data.User.Attributes[0].Value;
let confirm_data = await confirm_user(sub_id, password);
}
let EMAIL = 'foo#bar.com';
let PASSWORD = 'MY_PASSWORD';
main(EMAIL, PASSWORD)
Since I want to get the user's Identity Pool ID (as identityID variable here) I need to define a third function that I name as authenticate_user(email, password):
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');
async function authenticate_user(email, password) {
var authenticationData = {
Username: email,
Password: password,
};
let auth_details = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);
let poolData = {
UserPoolId : USER_POOL_ID,
ClientId : AWS_COGNITO_CLIENT_ID
};
let pool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
let userData = {
Username: email,
Pool: pool
};
let cognito_user = new AmazonCognitoIdentity.CognitoUser(userData);
let jwt_token;
await new Promise((resolve) => {
cognito_user.authenticateUser(auth_details, {
onSuccess: (result) => {
jwt_token = result.getIdToken().getJwtToken();
return resolve(jwt_token);
},
onFailure: (err) => {
return resolve(err.message || JSON.stringify(err) );
},
});
});
let logins = {};
logins["cognito-idp." + AWS_REGION + ".amazonaws.com/" + USER_POOL_ID] = jwt_token;
let creds = new AWS.CognitoIdentityCredentials({
IdentityPoolId: AWS_COGNITO_IDENTITY_POOL_ID,
Logins: logins
});
let IdentityId;
await new Promise((resolve) => {
creds.get(function(err) {
IdentityId = creds.data.IdentityId;
resolve(IdentityId);
});
})
return IdentityId;
}
Apparently it is a very long and complex way of getting the user's identityID. Is there a simpler way to get the user federated Identity Pool ID? Aside from the complexity, we need to know the user password to get the user's Identity Pool ID. Is there a way to get it without knowing the user's password?

Related

MongoDB only using one entry - Discord.js

Currently I have a command of which checks someone else's balance with my sort of economy system. The issue is that it's only storing one users data - so when the database is empty and the bot goes to create a profile for a user that is the only profile ever created - for example when another member goes to check their balance then it won't show their own profile but it shows only the first person to create a profile's balance. I've tried everything - nothing works. Please help... Below is the command to check balance, my schema and the profile creating function.
if (message.author.bot) return;
let member = message.mentions.members.first();
if (member) {
if (message.content.match('!ponyo balance') && profileSchema.findOne({ memberId: member.id, guildId: member.guild.id })) {
console.log('trying to execute balance.createBalance() with the user id: ' + member.id)
const profileBalance = await balance.createBalance(member);
console.log(`profileBalance: ${profileBalance}`)
await message.reply(`${message.mentions.members.first()} has ${profileBalance.coins} coins! :D`);
}
}
})
const Balance = require('./profileSchema')
const mongoose = require('mongoose')
//create profile thingy
async function createBalance(member) {
if (Balance.findOne({ memberId: member.id })) {
let balanceProfile = await Balance.findOne({ memberId: member.id })
if (balanceProfile) {
return balanceProfile;
} else {
balanceProfile = await new Balance({
userID: member.id,
serverID: member.guild.id
});
await balanceProfile.save().catch(err => console.log(err));
console.log("returning: " + balanceProfile.toString());
return balanceProfile;
}}}
module.exports = { createBalance };
const mongoose = require('mongoose');
const profileSchema = new mongoose.Schema({
userID: { type: String, require: true, unique: true},
serverID: { type: String, require: true },
coins: { type: Number, default: 100 },
bank: { type: Number }
})
const model = mongoose.model('ProfileModels', profileSchema);
module.exports = model;
There is no memberId in your profile Schema..
if (Balance.findOne({ memberId: member.id })) {
Maybe you are mistakenly put memberId instead of userId or
you have Separate Balance Scheme.. which is not imported Correctly..

How to edit the MSAL login commands to make it work for multiple users?

I have the following code working and I'm able to login with username and password.
I am working with Cypress to login to a webapp with MSAL.
In the e2e Testfile:
describe('Login with MSAL as xxUsername', () => {
beforeEach(() => {
cy.LoginWithMsal()
})
Command.js:
import { login } from "./auth";
let cachedTokenExpiryTime = new Date().getTime();
let cachedTokenResponse = null;
Cypress.Commands.add("LoginWithMsal", () => {
if (cachedTokenExpiryTime <= new Date().getTime()) {
cachedTokenResponse = null;
}
return login(cachedTokenResponse).then((tokenResponse) => {
cachedTokenResponse = tokenResponse;
cachedTokenExpiryTime = new Date().getTime() + 50 * 60 * 1000;
});
});
Imported auth.js
/// <reference types="cypress" />
import { decode } from "jsonwebtoken";
import authSettings from "./authsettings.json";
const {
authority,
clientId,
clientSecret,
apiScopes,
username,
password,
} = authSettings;
const environment = "login.windows.net";
const buildAccountEntity = (
homeAccountId,
realm,
localAccountId,
username,
name
) => {
return {
authorityType: "MSSTS",
// This could be filled in but it involves a bit of custom base64 encoding
// and would make this sample more complicated.
// This value does not seem to get used, so we can leave it out.
clientInfo: "",
homeAccountId,
environment,
realm,
localAccountId,
username,
name,
};
};
const buildIdTokenEntity = (homeAccountId, idToken, realm) => {
return {
credentialType: "IdToken",
homeAccountId,
environment,
clientId,
secret: idToken,
realm,
};
};
const buildAccessTokenEntity = (
homeAccountId,
accessToken,
expiresIn,
extExpiresIn,
realm,
scopes
) => {
const now = Math.floor(Date.now() / 1000);
return {
homeAccountId,
credentialType: "AccessToken",
secret: accessToken,
cachedAt: now.toString(),
expiresOn: (now + expiresIn).toString(),
extendedExpiresOn: (now + extExpiresIn).toString(),
environment,
clientId,
realm,
target: scopes.map((s) => s.toLowerCase()).join(" "),
// Scopes _must_ be lowercase or the token won't be found
};
};
const injectTokens = (tokenResponse) => {
const idToken = decode(tokenResponse.id_token);
const localAccountId = idToken.oid || idToken.sid;
const realm = idToken.tid;
const homeAccountId = `${localAccountId}.${realm}`;
const username = idToken.preferred_username;
const name = idToken.name;
const accountKey = `${homeAccountId}-${environment}-${realm}`;
const accountEntity = buildAccountEntity(
homeAccountId,
realm,
localAccountId,
username,
name
);
const idTokenKey = `${homeAccountId}-${environment}-idtoken-${clientId}-${realm}-`;
const idTokenEntity = buildIdTokenEntity(
homeAccountId,
tokenResponse.id_token,
realm
);
const accessTokenKey = `${homeAccountId}-${environment}-accesstoken-${clientId}-${realm}-${apiScopes.join(
" "
)}`;
const accessTokenEntity = buildAccessTokenEntity(
homeAccountId,
tokenResponse.access_token,
tokenResponse.expires_in,
tokenResponse.ext_expires_in,
realm,
apiScopes
);
localStorage.setItem(accountKey, JSON.stringify(accountEntity));
localStorage.setItem(idTokenKey, JSON.stringify(idTokenEntity));
localStorage.setItem(accessTokenKey, JSON.stringify(accessTokenEntity));
};
export const login = (cachedTokenResponse) => {
let tokenResponse = null;
let chainable = cy.visit("https://xxxxxxxxxxxxx.nl/");
if (!cachedTokenResponse) {
chainable = chainable.request({
url: authority + "/oauth2/v2.0/token",
method: "POST",
body: {
grant_type: "password",
client_id: clientId,
client_secret: clientSecret,
scope: ["openid profile"].concat(apiScopes).join(" "),
username: username,
password: password,
},
form: true,
});
} else {
chainable = chainable.then(() => {
return {
body: cachedTokenResponse,
};
});
}
chainable
.then((response) => {
injectTokens(response.body);
tokenResponse = response.body;
})
.reload()
.then(() => {
return tokenResponse;
});
return chainable;
};
Got credentials in authSettings.json
{
"authority": "https://login.microsoftonline.com/x",
"clientId": "x",
"clientSecret": "x",
"apiScopes": [ "x" ],
"username": "xxUsername",
"password": "xxPassword"
}
As you can see I am able to login with the credentials which were saved as variable in the authSettings.json file. This is restricting me to use just 1 user to authenticate in my tests. What is the best practice to get logged in with any other usercredential?
Add users to the fixture keyed by an id
authsettings.json
{
"user1": {
"username": "xxUsername",
"password": "xxPassword"
...
},
"user2": {
"username": "xxUsername",
"password": "xxPassword"
...
},
...
}
In auth.js is gets a bit tricky since you have some closures on the initial import, for example
const buildIdTokenEntity = (homeAccountId, idToken, realm) => {
return {
credentialType: "IdToken",
homeAccountId,
environment,
clientId, // closure from above (not a parameter)
secret: idToken,
realm,
};
};
You could set the desired userid in an environment variable, so the top of auth.js becomes
import authSettings from "./authsettings.json";
const userId = Cypress.env('userId');
const {
authority,
clientId,
clientSecret,
apiScopes,
username,
password,
} = authSettings[userId];
In the tests,
it('tests user1', () => {
Cypress.env('userId', 'user1')
...
})
Also use a default in Cypress configuration
// cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
baseUrl: 'http://localhost:1234'
},
env: {
userId: 'user3'
}
})
Timing
The above is your smallest change, but I suspect it won't work since Command.js is imported in cypress/support/e2e.js and executes the auth.js import before the test runs.
If that's the case, you will need to pass userId into the login
test
describe('Login with MSAL as xxUsername', () => {
beforeEach(() => {
cy.LoginWithMsal('user2')
})
Commands.js
Cypress.Commands.add("LoginWithMsal", (userId) => { // receive here
if (cachedTokenExpiryTime <= new Date().getTime()) {
cachedTokenResponse = null;
}
return login(cachedTokenResponse, userId) // pass here
.then((tokenResponse) => {
cachedTokenResponse = tokenResponse;
cachedTokenExpiryTime = new Date().getTime() + 50 * 60 * 1000;
});
auth.js
import authSettings from "./authsettings.json";
let // const -> let to allow change
authority,
clientId,
clientSecret,
apiScopes,
username,
password;
...
export const login = (cachedTokenResponse, userId) => {
authority = authSettings[userId].authority;
clientId = authSettings[userId].clientId;
clientSecret = authSettings[userId].clientSecret;
apiScopes = authSettings[userId].apiScopes;
username = authSettings[userId].username;
password = authSettings[userId].password;
...
You could reduce that down if some of the credentials are common to all users.

store agent SessionsClient of dialogflow api

I'm integrating dialogflow in my chat, but i'm having a problem. I can't figure out how can i store the session with the agent
async startSession({projectId, google_app_credencials}) {
process.env.GOOGLE_APPLICATION_CREDENTIALS = google_app_credencials;
const sessionId = uuid.v4();
const sessionClient = new dialogflow.SessionsClient();
const sessionPath = await sessionClient.projectAgentSessionPath(projectId, sessionId)
await sessionClient.initialize();
return {
sessionId: sessionId,
sessionClient: sessionClient,
sessionPath: sessionPath,
};
}
async sendMessageAndGetResponse(message, {sessionPath, sessionClient}) {
const request = {
session: sessionPath,
queryInput: {
text: {
text: message,
languageCode: 'pt-BR',
},
},
};
const responses = await sessionClient.detectIntent(request);
const result = responses[0].queryResult;
return {
response: result.fulfillmentText,
fields: result.parameters.fields,
}
}
I need the return of startSession in every call of sendMessageAndGetResponse and i need to store then e my nodejs server. but my attempts of store SessionsClient in redis failed. Now i wanna know if there is a way of re establish the connection with the agente just with the SessionPath in the future calls.
//attempt to save in redis
let dialogflowBot = {
projectId: dialogflow.project_name,
google_app_credencials: DialogflowHelper.getCredentialsPath(dialogflow)
}
dialogflowBot.bot = await DialogflowHelper.startSession(dialogflowBot);
redisClient.set(filaChat.id_registro, JSON.stringify(dialogflowBot));
//error: Converting circular structure to JSON
//Can't save the sessionClient
how can i save the SessionClient for call him again later, or save just the SessionPath for re establish the connection again?
I solved this just saving the SessionId and passing this same id in future calls instead of generating a new one
async reestablishSession({projectId, google_app_credentials, sessionId}) {
process.env.GOOGLE_APPLICATION_CREDENTIALS = google_app_credentials;
const sessionClient = new dialogflow.SessionsClient();
const sessionPath = await sessionClient.projectAgentSessionPath(projectId, sessionId)
await sessionClient.initialize();
return {
sessionId: sessionId,
sessionClient: sessionClient,
sessionPath: sessionPath,
};
}

Firebase writing data with variable via REST

in my app I am getting the uid of the current user by:
also I get the username from :
console.log gives me the right name.
But when I try to write to my db via:
https://movieapp-8a157.firebaseio.com/users/${username}/${authUser}/posts.json?auth=${token}
It doesnt work. If I remove the ${username} it will write in the correct path. Any ideas? I edited my post for more clearness.
export const postJob = data => {
return async (dispatch, getState) => {
const randomColors = ["#f3a683"];
const colorNumber = Math.floor(Math.random() * 20) + 1;
const bgColor = randomColors[colorNumber];
const val = getState();
const userId = val.auth.userId;
const rules = {
description: "required|min:2"
};
const messages = {
required: field => `${field} is required`,
"description.min": "job description is too short"
};
try {
await validateAll(data, rules, messages);
const token = await firebase
.auth()
.currentUser.getIdToken(true)
.then(function(idToken) {
return idToken;
});
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
var displayName = user.displayName;
var email = user.email;
var emailVerified = user.emailVerified;
var photoURL = user.photoURL;
var isAnonymous = user.isAnonymous;
var uid = user.uid;
var providerData = user.providerData;
// ...
} else {
// User is signed out.
// ...
}
});
var user = firebase.auth().currentUser;
const authUser = user.uid;
const username = await firebase
.database()
.ref("users/" + authUser + "/name")
.once("value", function(snapshot) {
console.log("################", snapshot.val());
});
//console.log("#####################", authUser);
const response = await fetch(
`https://movieapp-8a157.firebaseio.com/users/${username}/${authUser}/posts.json?auth=${token}`,
{
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
titel: data.titel,
fname: data.fname,
description: data.description,
cover: data.cover,
friend: data.friend,
ownerId: userId,
bgColor: bgColor
})
}
);
const resData = await response.json();
Your code that's getting the UID isn't working the way you exepct. The auth state listener is asynchronous and is triggering after the line of code that accessesfirebase.auth().currentUser. That line of code is actually giving you the current user before the sign-in completes. That means it's going to be undefined.
You're then using that undefined value to build a reference to a location in the database. This is causing the actual reference to be something other than what you expect. You should add debug logging to see this yourself.
You should be using the callback to determine when exactly the user is signed in, and only read and write that user's location. This means that you should probably move the lines of code that write the database into the callback, when you know that user is correct, and use user.uid to build the database reference for reading and writing.

Firebase Cloud functions timeout

The following function works well when tested with shell, and data are created in firestore.
When pushed in prod, it returns Function execution took 60002 ms, finished with status: 'timeout'
Any input?
exports.synchronizeAzavista = functions.auth.user().onCreate(event => {
console.log('New User Created');
const user = event.data;
const email = user.email;
const uid = user.uid;
return admin.database().ref(`/delegates`)
.orderByChild(`email`)
.equalTo(email)
.once("child_added").then(snap => {
const fbUserRef = snap.key;
return admin.firestore().collection(`/users`).doc(`${fbUserRef}`).set({
email: email,
uid: uid
}).then(() => console.log("User Created"));
});
});
Edit
I've update my code with the following, but I still getting Function returned undefined, expected Promise or value but I can't identify where my function return undefined. Why my getUser() function does not return anything?
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.synchronizeAzavista = functions.auth.user().onCreate(event => {
console.log('New User Created');//This log
const user = event.data;
const email = user.email;
const uid = user.uid;
console.log('Const are set');//This log
getUser(email).then(snap => {
console.log("User Key is " + snap.key);//No log
const fbUserRef = snap.key;
return admin.firestore().collection(`/users`).doc(`${fbUserRef}`).set({
email: email,
uid: uid
});
}).then(() => console.log("User Data transferred in Firestore"));
});
function getUser(email) {
console.log("Start GetUser for " + email);//This log
const snapKey = admin.database().ref(`/delegates`).orderByChild(`email`).equalTo(email).once("child_added").then(snap => {
console.log(snap.key);//No Log here
return snap;
});
return snapKey;
}
You're not returning a promise from your write to Firestore.
exports.synchronizeAzavista = functions.auth.user().onCreate(event => {
const user = event.data;
const email = user.email;
const uid = user.uid;
return admin.database().ref(`/delegates`)
.orderByChild(`email`)
.equalTo(email)
.once("child_added").then(snap => {
const fbUserRef = snap.key;
return admin.firestore().collection(`/users`).doc(`${fbUserRef}`).set({
email: email,
uid: uid
});
});
});

Categories

Resources