Another user's data coming when user signup using GUN JS - gun

when i create a new user in browser 1, its working success.
in browser 1
when i create a new user in browser 2, the browser 1 data also coming in localStorage.
in browser 2
await user.create(signupEmail, signupPassword, async ({ err }) => {
if (err) {
console.log(err)
} else {
console.log(user)
console.log(user.is.pub)
let userData = {
FirstName : this.signupEmail,
LastName : this.signupEmail,
PublicKey : user.is.pub
}
var meData = gun.get('Me');
var me = meData.set(userData); // create all users in Me table
var mePubData = gun.get(user.is.pub).put({MeId : me});
}
});
I don't want user 1 data in browser 2. what is wrong on this code ? Please help me.. Thanks

Related

Firebase updatePassword removes sign_in_second_factor phone property from token

I do a reautenticate with a user whom is already logged in as a Multifactor user
async reauthenticate(oldPassword: string): Promise<SignInEmailPassword> {
const user = firebase.auth().currentUser;
try {
if (user?.email) {
const cred = firebase.auth.EmailAuthProvider.credential(user.email, oldPassword);
await user.reauthenticateWithCredential(cred);
}
return { exception: '', token: '' };
} catch (reason) {
let phoneNumber = '****';
if ((reason as any).code === 'auth/multi-factor-auth-required') {
// The user is enrolled in MFA, must be verified
this.mfaResolver = (reason as any).resolver;
phoneNumber = (reason as any).resolver.hints[0].phoneNumber;
}
return { exception: 'auth/multi-factor-auth-required', phoneNumber };
}
}
I do the phone verification like
const phoneAuthProvider = new firebase.auth.PhoneAuthProvider();
const phoneOpts = {
multiFactorHint: this.mfaResolver.hints[0],
session: this.mfaResolver.session,
};
try {
this.verificationId = await phoneAuthProvider.verifyPhoneNumber(phoneOpts, recaptcha);
All good so far ( the recaptcha works with some other code, not mentioned here )
Then the actual SMS is verified, like:
const cred = firebase.auth.PhoneAuthProvider.credential(this.verificationId, phoneCode);
const multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
const user = firebase.auth().currentUser;
try {
if (this.mfaResolver) {
await this.mfaResolver.resolveSignIn(multiFactorAssertion);
}
all good, and then finally
I can update the password with
const user = firebase.app().auth().currentUser;
if (user) {
await user.updatePassword(password);
}
If I console.log the token JUST before the updatePassword, I get my old token, with the
"sign_in_second_factor": "phone" property, but the token AFTER the updatePassword suddenly is without the sign_in_second_factor property, so basically it broke the token.
My solution is now to log out, and force the user to log back in ( again with MFA ), but an unnecessary step.
Is this avoidable,
to me it looks like a firebase bug, as it generates a valid token, WITHOUT a sign_in_second_factor being present, while it is a MFA firebase user.

How to switch accounts in react native

I'm trying to build react native app in which user will have option to switch multiple accounts, similar to Instagram. My problem is, How to change user data on when user switches account.
You can use react-native-keychain to store the Active User and User List. This will store the data in Device.
const StoreData = async () => {
let activeUser = 'User1'
let userList = [
{ ID: 'User1' },
{ ID: 'User2' }
]
userList = JSON.stringify(userList)
await Keychain.setGenericPassword(activeUser, userList); // Note: activeUser and userList should be string.
}
const RetrieveData = async () => {
try {
const credentials = await Keychain.getGenericPassword();
if (!credentials)
return console.log('No credentials stored')
let { username: activeUser, password: userList } = credentials
userList = JSON.parse(userList)
return console.log({ activeUser, userList })
} catch (error) {
return console.log("Keychain couldn't be accessed!", error);
}
}
If you are using library similar to Redux, MobX, ... You can use them to refresh the APP with the selected user.
One way you could do this is by having the token of the other users and then retrieve all the user data everytime you switch users.

cognito custom auth (CUSTOM_CHALLENGE) ignore retry because session expiration

my goal is to implement otp by sending a sms to user mobile. im able to achieve this using cognito custom auth flow, but, only works if the user success in the firts attemp, if the user enter a bad code, the session is gonna expire and a new code is required to be sent again, bad ux. i do need at least 3 attemps, which in theory are 3 sessions across this cognito auth flow.
im gonna share the four cognito lambdas (cognito triggers) i used for this: preSignUp, defineAuthChallenge, createAuthChallenge and verifyChanllenge
// preSignUp lambda
exports.handler = async (event) => {
event.response.autoConfirmUser = true;
event.response.autoVerifyPhone = true;
return event;
};
// defineAuthChallenge
exports.handler = async (event, context, callback) => {
if (event.request.session.length >= 3 && event.request.session.slice(-1)[0].challengeResult === false) {
// wrong OTP even After 3 sessions? FINISH auth, dont send token
event.response.issueToken = false;
event.response.failAuthentication = true;
} else if (event.request.session.length > 0 && event.request.session.slice(-1)[0].challengeResult === true) {
// Last answer was Correct! send token and FINISH auth
event.response.issueTokens = true;
event.response.failAuthentication = false;
} else {
// INIT flow - OR - not yet received correct OTP
event.response.issueTokens = false;
event.response.failAuthentication = false;
event.response.challengeName = 'CUSTOM_CHALLENGE';
}
return event;
};
// createAuthChallenge
exports.handler = async (event, context) => {
if (!event.request.session || event.request.session.length === 0) {
// create only once the otp, send over sms only once
var otp = generateOtp();
const phone = event.request.userAttributes.phone_number;
sendSMS(phone, otp);
} else {
// get previous challenge answer
const previousChallenge = event.request.session.slice(-1)[0];
otp = previousChallenge.challengeMetadata;
}
event.response = {
...event.response,
privateChallengeParameters: {
answer: otp
},
challengeMetadata: otp // save it here to use across sessions
};
return event
}
// verifyChanllenge
exports.handler = async (event, context) => {
event.response.answerCorrect = event.request.privateChallengeParameters.answer === event.request.challengeAnswer;
return event
}
for the client, which is a RN app, im using amplify, this is the flow in the app:
// SignIn form screen
import { Auth } from "aws-amplify";
const signUp = (phone) => {
Auth.signUp({
username: phone,
/** dummy pass since its required but unused for OTP */
password: "12345678"
}).then(() => {
// after signup, go an automatically login (which trigger sms to be sent)
otpSignIn(phone);
}).catch(({code}) => {
// signup fail because user already exists, ok, just try login it
if (code === SignUpErrCode.USER_EXISTS) {
otpSignIn(phone)
} else {
...
}
})
}
const otpSignIn = async (phoneNumber) => {
const cognitoUser = await Auth.signIn(phoneNumber)
setCognitoUser(cognitoUser);
navigate("ConfirmNumber", {phoneNumber});
}
import { Auth } from "aws-amplify";
let cognitoUser;
export function setCognitoUser(user) {
console.log('setCognitoUser', user)
cognitoUser = user;
}
export function sendChallenge(challengeResponse) {
return Auth.sendCustomChallengeAnswer(cognitoUser, challengeResponse)
}
// Confirm number screen
const onChangeText = (value) => {
if (value.length === 4) {
try {
const user = await sendChallenge(value)
// WEIRD THING NUMBER 1
// when the user send the second attempt, no error is raised, this promise is resolve!
// even when the trigger *verifyChanllenge* is returning false.
} catch (err) {
// WEIRD THING NUMBER 2
// from the trigger *createAuthChallenge* if i define the anser in the if block,
// and not store such answer for future use (i do that in else block), then,
// for the second..third attempt the error raised here is that *Invalid session for user* which mean session has expired,
// what i need is to persist session until third attempt
}
}
}
// this is amplify config: try 1
const awsExports = {
Auth: {
region: ...,
userPoolId: ...,
userPoolWebClientId: ...,
authenticationFlowType: 'CUSTOM_AUTH',
},
...
}
Amplify.configure(awsExports);
// this is amplify config: try 2
import {Auth} from "aws-amplify"
Auth.configure({
authenticationFlowType: 'CUSTOM_AUTH'
});
everything is correct in the code above, and the config for amplify authenticationFlowType: 'CUSTOM_AUTH' is not necessary.
the problem is that Auth.sendCustomChallengeAnswer(cognitoUser, challengeResponse) is not raising an error when the trigger defineAuthChallenge set this combination:
event.response.issueTokens = false;
event.response.failAuthentication = false;
event.response.challengeName = 'CUSTOM_CHALLENGE';
which presents the next attempt.
so i found a way to check the error when the user fail the otp:
const sendCode = async (value) => {
try {
// send the answer to the User Pool
// this will throw an error if it's the 3rd wrong answer
const user = await sendChallenge(value);
// the answer was sent successfully, but it doesnt mean it is the right one
// so we should test if the user is authenticated now
// this will throw an error if the user is not yet authenticated:
await Auth.currentSession();
} catch (err) {
setError(true);
}
}

How to use c8yClient code in the Angular 6 App (typescript file)

For Example:
import { Client } from '#c8y/client';
const baseUrl = 'https://demos.cumulocity.com/';
const tenant = 'demos';
const user = 'user';
const password = 'pw';
(async () => {
const client = await Client.authenticate({
tenant,
user,
password
}), baseUrl);
const { data, paging } = await client.inventory.list();
// data = first page of inventory
const nextPage = await paging.next();
// nextPage.data = second page of inventory
})();
Consider that I have login module in an angular 6 application. How to use this above code and authenticate the user in the login.component.ts file?
Cumulocity has released a demo on Stackblitz how to log in the user. Basically you build a ngForm with username, password and tenant and pass that to the Cumulocity client:
async login() {
const client = new Client(new BasicAuth(
{
user: this.model.user,
password: this.model.password,
tenant: this.model.tenant
}),
`https://${this.model.tenant}.cumulocity.com`
);
try {
let user = await client.user.current();
this.cumulocity.client = client;
} catch (ex) {
this.cumulocity.client = null;
this.error.shown = true;
this.error.msg = ex.message;
}
}
In this case this.model is the data coming from an ngFrom and on button click the login()? function is executed. The this.cumulocity variable contains a service so that you can share the logged in client with other components.
Note: If you run this on a different server (not hosted), then you need to enable CORS in the Cumulocity administration.

React Native - Download image from Facebook profile?

I'm using React Native FBSDK to integrate my app's user profiles with their Facebook. I'm looking for a way to allow the user to download images from their Facebook to my app. Similar to how this functions in Tinder.
To do that you need to do a graph request on Facebook to get more informations about a specific user.
That look something like that :
//first you need to sign in your user and then ...
let result = await this.FBGraphRequest('id, email, picture.type(large), last_name, first_name');
FBGraphRequest = async (fields) => {
const accessData = await AccessToken.getCurrentAccessToken();
this.saveToken(accessData["accessToken"], "facebook");
// Create a graph request asking for user information
return new Promise((resolve, reject) => {
const infoRequest = new GraphRequest('/me', {
accessToken: accessData.accessToken,
parameters: {
fields: {
string: fields
}
}
},
(error, result) => {
if (error) {
console.log('Error fetching data: ' + error.toString());
reject(error);
} else {
resolve(result);
}
});
new GraphRequestManager().addRequest(infoRequest).start();
});
};
To have much informations I redirect you to this great medium post.