Meteor.users.update() does not work on logout + login - javascript

I have a user profile view where users can edit their profile information. Everything below works great and the update is successful. However, when I logout of the account and login with a different user account, the update fails and returns an Access denied error. It isn't until I refresh the page that I can edit the profile information again with the second account.
I know this case is very rare and a user would not normally be logging out of one account, logging in with another and trying to update their profile but I would like to better understand why this is happening. Is the client token not flushed when a user logs out or is there something else that's being preserved that requires a complete reload of the page?
On client JS:
Template.user_profile_form.events({
'click #submit_profile_btn': function(evt) {
evt.preventDefault();
var first_name = $('#profile_first_name').val()
,last_name = $('#profile_last_name').val()
,email = $('#profile_email').val()
,email_lower_case = email.toLowerCase()
,gravatar_hash = CryptoJS.MD5(email_lower_case)
;
gravatar_hash = gravatar_hash.toString(CryptoJS.enc.Hex);
// TODO need to create user sessions so that when you log out and log back in, you have a fresh session
Meteor.users.update({_id: this.userId }, {
$set: {
profile: {
first_name: first_name,
last_name: last_name,
gravatar_hash: gravatar_hash
}
}
}, function(error) {
if (!error) {
Session.set('profile_edit', 'success');
Meteor.setTimeout(function() {
Session.set('profile_edit', null);
}, 3000);
} else {
Session.set('profile_edit', 'error');
Template.user_profile_form.error_message = function() {
return error.reason;
};
}
});
Meteor.call('changeEmail', email);
}
});
The server JS:
Meteor.publish('list-all-users', function () {
return Meteor.users.find({_id: this.userId }, {
fields: {
profile: 1,
emails: 1
}
});
});
Meteor.methods({
sendEmail: function(to, from, subject, text) {
this.unblock();
Email.send({
to: to,
from: from,
subject: subject,
text: text
});
},
changeEmail: function(newEmail) {
// TODO Need to validate that new e-mail does not already exist
Meteor.users.update(Meteor.userId(), {
$set: {
emails: [{
address: newEmail,
verified: false
}]
}
});
}
});
The template:
<template name="user_profile_form">
<h2>Update Profile</h2>
<div id="profile-form">
{{#if success}}
<div class="alert alert-success">
<strong>Profile updated!</strong> Your profile has been successfully updated.
</div>
{{/if}}
{{#if error}}
<div class="alert alert-error">
<strong>Uh oh!</strong> Something went wrong and your profile was not updated. {{error_message}}.
</div>
{{/if}}
<p>
{{#each profile}}
<input type="text" id="profile_first_name" placeholder="First Name" value="{{first_name}}">
<input type="text" id="profile_last_name" placeholder="Last Name" value="{{last_name}}">
{{/each}}
<input type="email" id="profile_email" placeholder="Email" value="{{email_address}}">
</p>
</div>
<div id="submit-btn">
<input type="submit" id="submit_profile_btn" class="btn btn-primary">
</div>
</template>

The Meteor logout function does almost nothing. It certainly does not tear down Session state or the rest of your app's context. Your code must reset these variables during your app's logout event. A manual refresh of the page causes the client side JavaScript to reload wiping out existing Session data.

If you don't want to mess with the accounts-ui template internals you can use the following pattern (CoffeeScript code) to clear individual variables from the Session:
Deps.autorun (c) ->
user = Meteor.user()
if user
# Setup code on login (if required)
else if not user
# Clear session on logout
Session.set "profile_edit", undefined

Related

Vue.js & Vuex - Store access token in store and redirect user to an URL for login

I'm trying to store the access token into the createStore (index.js) and then redirect the user to go to another webpage once they login.
For this I need to create a mutation within mutations.js so that I can set the access token and set the refresh token. The refresh should be like a time stamp.
The test.vue is where the login code is to validate the user.
So, basically I need to create a function, set the access token, set the refrefresh token and then redirect the user to another webpage once they pressh the login button.
Many thanks in advance!
index.js:
import vuex from 'vuex';
import mutations from './mutations';
const createStore = () =>{
return new vuex.Store({
state: {
accessToken: "halo",
access_token: response.data.access_token,
refresh: response.data.refresh_token
},
getters:{
accessToken(state, getters){
return state.accessToken;
}
},
mutations
});
};
export default createStore;
mutations.js:
const mutations = {
setToken(state, token) {
state.accessToken = token;
}
}
export default mutations;
test.vue:
<template>
<form>
<div class="login">
<div>
<input name="email" type="text" v-model="email" v-validate="'required'" placeholder="Email" class="eSection" id="email">
<p v-show="wrong.email">
Email is missing or incorrect. Please try again!
</p>
<i name="emailFormat" type="text" v-validate="'required|emailFormat'" placeholder="Email" class="eSection" id="email"></i>
<p v-show="wrong.emailFormat">
Not valid email!
</p>
<input name="password" type="password" v-model="password" v-validate="'required'" placeholder="Password" class="pSection"
id="password">
<p v-show="wrong.password">
Password is missing or incorrect. Please try again!
</p>
<p v-show="wrong.all">
Login Details Incorrect!
</p>
<button type="button" class="log" #click="login">LogIn</button>
</div>
</div>
</form>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
email: "test#gmail.com",
password: "123456",
flag: false,
wrong: {
email: false,
emailFormat: false,
password: false,
all: false
},
}
},
methods: {
login: function (index) {
this.wrong.email = false;
this.wrong.password = false;
this.wrong.all = false;
this.wrong.emailFormat = false;
axios.post(`https://api.ticket.co/auth/login`, {
email: this.email,
password: this.password
})
.then(response => {
// JSON responses are automatically parsed.
console.log(response.data)
console.log(response.status)
})
.catch(e => {
console.log(e)
console.log(e.response.status)
var vueObject = this
switch (e.response.status) {
case 400:
if (!vueObject.email) {
console.log(1)
this.wrong.email = true;
} else if (!vueObject.emailFormat) {
console.log(2)
this.wrong.emailFormat = true;
};
if (!vueObject.password) {
console.log(3)
this.wrong.password = true;
}
break;
case 401:
console.log(4)
this.wrong.all = true;
break;
}
})
},
},
}
</script>
I think there are two possible solution for this problem.
First: you can use vue-router. In that case, there will be no
page refresh, just component change. That way untill you refresh
the page, every vuex state will live. (But its not the best
solution).
Second; You can write a rest call, what is give you back the actual
user token, if the user authenticated. So only this rest api call use
session authentication and / or CSRF token (check wiki if you
don't know it). One of the most elegant way if you use axios
interceptor (run before every axios call), what will get the token if
the user is authenticated. Check this github comment for futher
information. (Make sure, that session timeout is longer then token
lifetime :) )

Vuejs: Show error messages as popups

I have created a login section using Vuex and Axios to authenticate the login by allowing the user to enter the email and password. I have created and stored the variables I need by using a getter. I have also, placed the tokens I needed into a function, post url and console.
But, know I need to show the responses according to the tokens being seen in the inspector/console.
What I need is to show the error messages when the user tries to login. So, when the console responds showing 200 (email and password is correct) I need it to store that token, when the console responds showing 400 (incorrect/missing characters in either email or password) I need it to print out the error messages that I have already placed with an array, lastly, when the console responds showing 401 (both email and password incorrect) I need it to print out the messageFour that is in the array.
HTML:
<template>
<form>
<div class="login">
<div>
<input type="text" v-model="email" placeholder="Email" class="eSection" id="email">
<p v-for="message in errorM" :key="message.errorM" v-show="message in errorM">
{{ message }}
</p>
<input type="password" v-model="password" placeholder="Password" class="pSection" id="password">
<p v-for="message in errorM" :key="message.errorM">
{{message}}
</p>
<button type="button" class="log" #click="login">LogIn</button>
</div>
</div>
</form>
</template>
Javascript:
<script>
import axios from 'axios';
export default {
data() {
return {
email: "test#gmail.com",
password: "123456",
flag: false,
errorM:[],
errorMessages: [
{
messageOne: "The email that has been entered is incorrect. Please try again!"
},
{
messageTwo: "Email/Password is missing. Please try again!"
},
{
messageThree: "The password that has been entered is incorrect. Please try again!"
},
{
messageFour: "Both Email and Password that have been entered are incorrect!"
},
]
}
},
methods: {
login: function (index) {
axios.post(`https://api.ticket.co/auth/login`, {
email: this.email,
password: this.password
})
.then(response => {
// JSON responses are automatically parsed.
console.log(response.data)
console.log(response.status)
})
.catch(e => {
console.log(e)
console.log(e.response.status)
var vueObject = this
switch (e.response.status) {
case 400:
if(!vueObject.email || !vueObject.password){
vueObject.errorM.push(vueObject.errorMessages.messageTwo)
};
if(!vueObject.email){
vueObject.errorM.push(vueObject.errorMessages.messageOne)
};
if(!vueObject.password){
vueObject.errorM.push(vueObject.errorMessages.messageThree)
};
break;
case 401:
if(vueObject.email && vueObject.password == ""){
vueObject.errorM.push(vueObject.errorMessages.messageFour)
}
break;
}
})
},
},
}
</script>
Many thanks!
It's not clear from the description what's not working, so I'll just point out some issues I see.
One thing to mention is, there is no evidence of you using vuex, no getters, no setters, no state.
Most notable is that you have the messages defined as an array of objects, which makes it difficult to look up
instead of this, which is harder to look up:
errorMessages: [
{
messageOne: "The email that has been entered is incorrect. Please try again!"
},
// etc... {}, {}, {}
]
... you should do
errorMessages: {
messageOne: "The email that has been entered is incorrect. Please try again!",
messageTwo: "Email/Password is missing. Please try again!",
messageThree: "The password that has been entered is incorrect. Please try again!",
messageFour: "Both Email and Password that have been entered are incorrect!",
}
so that you can find a message using this.errorMessages.messageTwo
Or better yet, define it outside of your vue component, since you're not using them in your template
const MESSAGE_INCORRECTEMAIL = "The email that has been entered is incorrect. Please try again!";
const MESSAGE_MISSINGFIELD = "Email/Password is missing. Please try again!";
const MESSAGE_INCORRECTPASSWORD = "The password that has been entered is incorrect. Please try again!";
const MESSAGE_INCORRECTEMAILPASSWORD = "Both Email and Password that have been entered are incorrect!";
and then just call them as MESSAGE_MISSINGFIELD from your script
From security standpoint, it's a bad idea to indicate whether the username or the password is wrong, as it makes hacking easier by confirming what usernames exist.
You can determine if the user had errors or fields are missing before sending the form for remote processing.
to do that, you would call
login: function (index) {
if (this.email.trim() === '' || vueObject.password.trim() === ''){
this.errorM.push(MESSAGE_MISSINGFIELD);
return // <- prevents further execution
}
// repeat for other local validations before remote request
// ... then process request
axios.post(`https://api.ticket.co/auth/login`, {
anyway, you might also need t break your question up into individual errors you encounter.

Firebase: Email verification and user login to be able to access the page

I have created a form "main.html#!/register" to allow users to enter their: firstname, lastname, email and login. Once all those entered an email verification is sent, so that they cannot get to the page "main.html#!/success" before verifying the email.
The good news is: If they try to get to the access page from the login page without confirming the Email, they will not be able to access.
The bad news is: Right after the registration, if they enter the "main.html#!/success" they will be able to open this page !!
Use case:
The user is not able to access to "main.html#!/success" without any registration
The user is not able to access the "main.html#!/success" from the login page "main.html#!/login", if he has not verified his email
The problem is : The user is able to access the "main.html#!/success" right after the registration without email confirmation.
Question:
How can I use the email verification condition user.emailVerified and the user auth $requireSignIn() to allow the access to the page "main.html#!/success" ?
I had put a resolve function to prevent any access without the registration.
Here is my codes
1-resolve function:
Authentication is a service I have created
when('/success', {
templateUrl: 'views/success.html',
controller: 'SuccessController',
resolve: {
currentAuth: function(Authentication) {
return Authentication.requireAuth();
} //currentAuth
}//resolve
}).
2-code in the Authentication service
requireAuth: function() {
return auth.$requireSignIn();
}, //require Authentication
3- the register function (it is in the service)
register: function(user) {
auth.$createUserWithEmailAndPassword(
user.email,
user.password
).then(function(regUser) {
var regRef = ref.child('users')
.child(regUser.uid).set({
date: firebase.database.ServerValue.TIMESTAMP,
regUser: regUser.uid,
firstname: user.firstname,
lastname: user.lastname,
email: user.email
}); //userinfo
regUser.sendEmailVerification().then(function() {
// Email sent.
alert("your Email is verified: " + regUser.emailVerified) ;
}).catch(function(error) {
// An error happened.
alert(error);
});
}).catch(function(error) {
$rootScope.message = error.message;
}); //createUserWithEmailAndPassword
} //register
3- login function
login: function(user) {
auth.$signInWithEmailAndPassword(
user.email,
user.password
).then(function(user) {
if(user.emailVerified){
$location.path('/success');
}
else{
$rootScope.message= "Please validate your registration first : "+user.emailVerified;
}
}).catch(function(error) {
$rootScope.message = error.message;
}); //signInWithEmailAndPassword
}, //login
You are trying to enforce this on the client side. Instead you should enforce access for verified signed in users from your Firebase rules. For example:
".write": "$user_id === auth.uid && auth.token.email_verified == true"

Retrieving records in ember js

I'm new to ember js. I have a form & when a user hit submit i want to check whether the username & password that user have entered, is already in my model/database.I tried following,But it didn't work. Please help me with this...
Template
<h2>Welcome to my blog</h2>
<form {{action 'exist' on="submit"}}>
<dl>
<dt>User Name:<br> {{textarea value=uName cols="20" rows="1"}}</dt>
<dt>Password:<br> {{textarea value=passw cols="20" rows="1"}}</dt>
</dl>
<button type="submit" class="btn btn-primary">Login</button>
</form>
Model
import DS from 'ember-data';
export default DS.Model.extend({
FirstName: DS.attr('string'),
UserName: DS.attr('string'),
Password: DS.attr('string'),
PermissionList: DS.attr('array')
});
Route
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.find('user');
}
});
Controller
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
ght: function () {
var uName = this.get('uName');
var passw = this.get('passw');
if (this.store.find('user', {
userName: this.get('uName')
})) {
alert('Already exist');
}
}
}
});
// This alert is shown for every input.Even they are not in the model
as store.find() always returns a promise which is an object, if condition always evaluates to true. What you should probably do is you've to wait for the promise to resolve and do the check like
// ...
var uName = this.get('uName');
this.store.find('user', {
userName: uName
}).then(function(user) {
if(user) {
alert('Already exist');
} else {
}
});
// ...
This form looks like a login form. If my assumption is right you don't show this form if user is already logged in ( in this case the session will have user info). In case if user is not logged in you will have to show form. I don't think you will need to search user in store. Just send/save user to server and do the user find logic on server side and send response accordingly. On ember side you can show exist result by handling .then of promises.
If your use case is different you can use query(for multiple records). and queryRecord for single record
Query
Copy pasted from documents
// GET to /persons?filter[name]=Peter
this.store.query('person', { filter: { name: 'Peter' } }).then(function(peters) {
// Do something with `peters`
});
// GET to /persons?filter[email]=tomster#example.com
this.store.queryRecord('person', { filter: { email: 'tomster#example.com' } }).then(function(tomster) {
// do something with `tomster`
});
//on mobile will add code if this doesn't help

Sign user in ONLY if email and password are correct?

I have a form that when you click submit it goes to the path /signin no matter what, even if you don't enter anything into the form. However I want it to check if there is a user with the email entered and if their password is correct before going to /signin. If the email is not known or the password is not correct then I want it to display an error (and stay on the log in page). I've been trying to get this to work but I'm not sure how to do it. Does anyone know how to do this? This is the code I have so far:
html:
<div id="topbar">
<h1><strong>chattly</strong></h1>
{{#unless currentUser}}
{{> signIn}}
{{> alert}}
{{else}}
{{> signOut}}
{{/unless}}
</div>
javascript:
// Sign In Template
Template.signIn.events({
'submit #signInForm': function(e, t) {
e.preventDefault();
var signInForm = $(e.currentTarget),
email = trimInput(signInForm.find('.email').val().toLowerCase()),
password = signInForm.find('.password').val();
if (isNotEmpty(email) && isEmail(email) && isNotEmpty(password) && isValidPassword(password)) {
Meteor.loginWithPassword(email, password, function(err) {
if (err) {
Session.set('alert', 'We\'re sorry but these credentials are not valid.');
} else {
Sesson.set('alert', 'Welcome back New Meteorite!');
}
});
}
return false;
},
});
You tagged this with iron-router so I assume you are using the iron router package.
You could prevent un-authenticated users from getting to any page beyond your login page by using before hooks on all the routes for restricted pages. The before hook would check Meteor.user() if it doesn't return an object there is no user logged in and it could re-route to the login page.
Checkout the iron-router documentation, here is the section on before and after hooks. It even shows using a before hook as a filter to prevent un-authenticated users from going to a route.
https://github.com/EventedMind/iron-router/#before-and-after-hooks
It looks something like this:
Router.map(function () {
this.route('postShow', {
path: '/posts/:_id',
before: function () {
if (!Meteor.user()) {
// render the login template but keep the url in the browser the same
this.render('login');
// stop the rest of the before hooks and the action function
this.stop();
}
},
action: function () {
// render the main template
this.render();
// combine render calls
this.render({
'myCustomFooter': { to: 'footer' },
'myCustomAside': { to: 'aside' }
});
},
after: function () {
// this is run after our action function
}
});
});

Categories

Resources