full email validation on Meteor using Mandrill - mandrill

I have read several SO posts about using Mandrill with Meteor.js for email validation, yet I've found a problem no others seem to face.
Ultimately, I want the verified property of a user to be set to true after clicking the email validation url. I am using Mandrill to send customized email templates containing a verification_url. I have the accounts-password and accounts-ui packages added. My code looks like this:
if (Meteor.isServer) {
Meteor.startup(function () {
Mandrill.config({
username: process.env.MANDRILL_API_USER,
key: process.env.MANDRILL_API_KEY
// port: 587, // defaults to 465 for SMTP over TLS
// host: 'smtp.mandrillapp.com', // the SMTP host
// baseUrl: 'https://mandrillapp.com/api/1.0/' // update this in case Mandrill changes its API endpoint URL or version
});
Accounts.config({
sendVerificationEmail: true
});
Accounts.emailTemplates.verifyEmail.html = function (user, url) {
var referralCode = Random.id();
var result;
try {
result = Mandrill.templates.render({
template_name: 'email-verification',
template_content: [],
merge_vars: [
{
name: 'SUBJECT',
content: 'my fancy subject'
},
{ name: 'EMAIL',
content: 'my fancy email'
},
{
name: 'VERIFICATION_URL',
content: 'http://localhost:3000/?ref=' + referralCode
}
]
});
} catch (error) {
console.error('Error while rendering Mandrill template', error);
}
return result.data.html;
};
});
When I create a user the verification email is correctly sent, however when I click the verification link within the email, nothing is done on the server, i.e. I look at my app's MongoDB and see on the user document still have the property verified: false. I've tried to work with onEmailVerificationLink (http://docs.meteor.com/#/full/Accounts-onEmailVerificationLink) but I get an error in the console saying onEmailVerificationLink has already been called, which happens because accounts-ui is apparently calling it for me. How do I do proper email verification in Meteor.js using Mandrill?

Finally figured it out. Instead of the line
content: 'http://localhost:3000/?ref=' + referralCode
I should replace it with
content: url
since Meteor is already creating the validation url for me, and passing it in through the "url" argument of the function. Clearly I didn't need referralCode either

Related

Changing Cognito-User-Pool/AWS-Amplify; leading to SignUp issue

I am, handling some SignUp/SignIn process within an iOS app, using AWS-Amplify (and Cognito).
It was working fine, but then I decided to require a few more information when signing up.
Namely: name, given_name, family_name.
Here is the function called to authenticate:
func showSignIn() {
AWSAuthUIViewController
.presentViewController(with: self.navigationController!,
configuration: nil,
completionHandler: {
(provider: AWSSignInProvider, error: Error?) in
if error != nil {
print("Error occurred: \(String(describing: error))")
} else {
print("Identity provider: \(provider.identityProviderName)")
}
})
}
After I did the necessary manipulations (using amplify-cli) to remove the old user pool and make a new one. I recompiled my iOS app and launched it.
This was OK, but now when I want to sign up a user I get this message:
The message content is not surprising, since now I require the indicated fields.
But the problem is that I don't see any space in the UI where to input those new fields.
Did I forget to do something so that the UI could be updated adequately?
Or am I suppose to do something (to update the UI by hand) by modifying the function above? If YES, what is the way to make the change?
These are my first steps with amplify, I may well be making some basic mistakes.
I'm only using AWS Amplify with JavaScript, but in JS you do need to update the UI manually.
Here is the JS code and how I have to call it manually, maybe this helps.
handleSignUpPressed = async ({
emailAddress = '',
firstName = '',
lastName = '',
password = '',
phoneNumber = '',
wantsToImproveApp = true,
} = {}) => {
if (emailAddress && firstName && lastName && password && phoneNumber) {
try {
const res = await Auth.signUp({
username: emailAddress,
password,
attributes: {
email: emailAddress,
name: firstName,
family_name: lastName,
phone_number: phoneNumber,
},
});
console.log('success', res);
this.props.navigation.push('VerificationScreen', {
username: res.username,
});
} catch (err) {
console.log(err);
}
}
};
You can use AWSMobileClient to show the drop-in Auth https://aws-amplify.github.io/docs/ios/authentication#user-attributes which is using AWSAuthUIViewController underneath the covers.
I didn't see a way to customize it with SignInUIOptions for your use case. There is also an existing RFC to improve the usability of AWSMobileClient and the drop-in UI: https://github.com/aws-amplify/aws-sdk-ios/issues/1158
If you roll your own sign-up/sign-in flow, you can then pass in user attributes to AWSMobileClient.signUp: https://aws-amplify.github.io/docs/ios/authentication#user-attributes

How can I send a POST request to start a password reset flow using axios

I'm implementing the Forgot password feature using truevault API. Now, I've been testing the requests following the flow with Postman, and it works, but, when I started coding using axios, it keeps throwing issues about authentication. I've tried several combinations (logical ones, not just random craziness).
Also, worth mentioning that I was able to list my truevault users from UI (not only postman), and tried to mimic the same principle to the post request, but it didn't work
Here is the postman request that worked for me:
for the url request, method is: POST
url: https://api.truevault.com/v1/password_reset_flows
For the Authorization tab, I filled the "username" field with the truevault user API Key, and left the "password" field empty
And the "Body" tab, I filled it with a Json text, and for radio button options, I selected raw, and picked json as the format. (these are the only tabs being used)
The json body is as follow
{
"name":"XXXXX password reset",
"sg_template_id":"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXcf42",
"sg_api_key":"XX.XXXXXXXXXXXXXXXXXXXXXX.XXXXXX_XXXX_XXXXXXXXXXXXXXXXXXXXXXXXXXZftJo",
"user_email_value_spec":{
"system_field":"username"
},
"from_email_value_spec":{
"literal_value":"do-not-reply#XXXXXX.com"
},
"substitutions":{
"{{FIRST_NAME}}":{
"user_attribute":"first_name"
}
}
}
And the result was successful,
Now, when I tried with axios, I kept getting the auth error. Code is as follows:
createPasswordResetFlow()
{
axios.defaults.headers.common["Authorization"] = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX27"; //tv user API KEY
axios.defaults.headers.post["Content-Type"] = "application/json";
var request = axios.post("https://api.truevault.com/v1/password_reset_flows",
{
auth:
{
username: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX27',
password: ""
},
data:
{
"name": "XXXXX password reset",
"sg_template_id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXcf42",
"sg_api_key": "XX.XXXXXXXXXXXXXXXXXXXXXX.XXXXXX_XXXX_XXXXXXXXXXXXXXXXXXXXXXXXXXZftJo",
"user_email_value_spec":
{
"system_field": "username"
},
"from_email_value_spec":
{
"literal_value": "do-not-reply#XXXXXX.com"
},
"substitutions":
{
"{{FIRST_NAME}}":
{
"user_attribute": "first_name"
}
}
}
})
.then((res) =>
{
console.log(res);
return res.data.users;
})
.catch(error =>
{
console.log('error', error);
return error;
});
}
As mentioned also earlier, I've been researching and trying, but to no avail, if someone could help me please.
There are two issues with the JS code you shared which are causing the problem:
The line where you set the default Auth header looks like this: axios.defaults.headers.common["Authorization"] = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX27"; //tv user API KEY. Note that the Authorization header is being set to the API key, not an HTTP Basic Auth header value. If you want to set the default auth header this way, you need to set it to base64(API_KEY:) rather than just API_KEY.
According to the axios docs the post method has the signature .post(url, data, config). As a result, your code is POSTing a JSON object that looks like {auth: ..., data: ...}.
Try removing the line where you set the authorization header, and changing the post call to look something like this:
axios.post("https://api.truevault.com/v1/password_reset_flows",
{
"name": "XXXXX password reset",
"sg_template_id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXcf42",
"sg_api_key": "XX.XXXXXXXXXXXXXXXXXXXXXX.XXXXXX_XXXX_XXXXXXXXXXXXXXXXXXXXXXXXXXZftJo",
"user_email_value_spec":
{
"system_field": "username"
},
"from_email_value_spec":
{
"literal_value": "do-not-reply#XXXXXX.com"
},
"substitutions":
{
"{{FIRST_NAME}}":
{
"user_attribute": "first_name"
}
}
}
}, {
username: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX27',
password: ""
})

Twitter: Error sending Direct message with quick reply buttons

I need to send a Twitter DM with quick reply.
I use Tweetinvi, that at the moment does not support quick replies, therefore I tried to alter the query in Tweetinvi code at the lovest possible level: just before it is sent to Twitter.
If I send this (basic message)
https://api.twitter.com/1.1/direct_messages/new.json?text=hello&user_id=999999999
It works
When I send is this
https://api.twitter.com/1.1/direct_messages/new.json?text=MessageToUserId&user_id=999999999&quick_reply&type=options&options=[label=RedBird&description=Adescriptionabouttheredbird.&metadata=external_id_1]
I get status 401 Web request failed.
To build my request I tried to simplify this example:
https://developer.twitter.com/en/docs/direct-messages/quick-replies/api-reference/options
But I am missing something. I suppose it is a trivial mistake in the query. I tried several variations, but I cannot get a better result. Of course in my code I use a real userId, that here I masked with 9.
Can you suggest me a working correction to my query? (maybe with examples using multiple labels)
Update.
I tried to use TwitterAccessor (without hacks in Tweetinvi code) and improved the json
Here is my updated code
Auth.SetUserCredentials(consumerKey, consumerSecret, userAccessToken, userAccessSecret);
var authenticatedUser = User.GetAuthenticatedUser();
var qString = JsonConvert.DeserializeObject("{ 'event': { 'type': 'message_create', 'message_create': { 'target': { 'recipient_id': '123456789' }, 'sender_id': '987654321', 'message_data': { 'text': 'option?', 'quick_reply': { 'type': 'options', 'options': [ { 'label': 'option 1', 'metadata': 'val1', 'description': 'option 2' }, { 'label': 'val2', 'metadata': 'option 3', 'description': 'val3' } ] } } } } }");
var strEncoded = WebUtility.HtmlEncode(qString.ToString());
var url = "https://api.twitter.com/1.1/direct_messages/events/new.json";
var result = TwitterAccessor.TryExecutePOSTQuery($"{url}?{strEncoded}");
Now I have error 401, with this description:
"Unauthorized - Authentication credentials were missing or incorrect."
Which is much better. Probably I just need to add credential headers using TwitterAccessor, but I need help about this.
I suppose that adding something TwitterAccessor. Method to create credentials headers before the post should do the job.

Rikulo security client side login

I've been trying to create a Dart SPA using Rikulo security to log in. I have been unable to do so successfully. I found the following in the docs:
//If you'd like to login in an Ajax request, SOAP or others,
//you can invoke this method directly by providing the username, password
//and, optional, rememberMe:
//prepare username, password, rememberMe from, say, Ajax
security.login(connect, username: username, password: password,
rememberMe: rememberMe, redirect: false);
My question is how do I return a success/fail login value from Rikulo security for use on the client side.
An example would be extremely helpful. Thanks in advance.
I assume you'd like to log in over Ajax (and JSON). Basically, it is no different from handling Ajax -- you can refer to the Handle Post requests section here.
import "dart:convert";
import "package:rikulo_commons/convert.dart";
Future login(HttpConnect connect) {
return readAsJson(connect.request).then((Map<String, String> data) {
return security.login(connect, redirect: false,
username: data["username"],
password: data["password"]);
})
.then((_) {
//login successfully
response
..headers.contentType = contentTypes["json"]
..write(JSON.encode({"result": "success"}));
})
.catchError((ex) {
if (ex is AuthenticationException) {
// login fail
response
..headers.contentType = contentTypes["json"]
..write(JSON.encode({'result': 'fail'}));
} else {
throw new Http404.fromConnect(connect);
}
});
}

How to send mail from a Domain/Service in Grails

I have this plugin installed, I want to send mails from a Service/Domain class method , I was doing like this
class TrainingService {
def mailService
public def sendMail() {
mailService.sendMail {
multipart true
to "abc#xyz.com"
subject "Hello,"
body 'How are you?'
}
}
I got error "Cannot invoke method sendMail() on null object", How to resolve this
I am missing the "from" attribute and if you're using multipart email, you should also fill in additional parts of the email, snippet from my code:
mailService.sendMail {
multipart true
from '"Some account" <someaccount#email.com>'
to 'anotheremail#somedomain.com'
bcc emailAddresses.toArray()
subject dto.title
body emailPart1
html g.render(
template: 'emailNotification',
model: [ name: dto.name ]
)
}
Have you configured your SMTP server. You need these entries in your config file for mail to work. Do you have these ?
grails {
mail {
host = "hostname"
pop_port = 25
username = "username"
password = "password"
type = "pop3"
}
}
you can find more information about the configuration here
I got this error when I was passing variables called 'from' and 'to' into the method that was using sendMail. Try renaming the sendMail method and making sure that you don't have any conflicting variable names.

Resources