Accessing Proxy Server address from my nodejs? - node.js

i'm using nodemailer to send a confirmation email on my project,
like so:
var mailOptions = {
from: "alex#account",
to: req.body.email,
subject: "Account Verification Token",
html: `<p>Hello,<br/> Please verify your account by clicking the link <br/> <a href=http://${req.headers.host}/confirmation/${token}>Click here to verify</a></p>\n`
};
Im sending an href link which contains req.headers.host which is my node adress localhost:6000, but I wish it to be my react adress localhost:4000, since its going to change later, I wish to have a variable jst like req.headers.host which will contain my react client's adress, is it possible? or I need to set it manually?

If the app is not server-side rendered, you can pass the React client's address from the frontend and include it to your request object which you can then retrieve after it gets to the server.

I found the answer I can use the variable :
const addr = `req.headers.referer`

Related

Having issues sending "base64" email "attachments" using "#sendgrid/mail" in "nodejs"

So, basically I want to send a base64 encoded .zip file as email attachment in #sendgrid/mail. The file is saved in MongoDB like this,
I am fetching the data and converting the "file.buffer" which is a binary data to base64 using .toString("base64") something like this,
console.log('Converting to base64')
plugin.file.buffer = plugin.file.buffer.toString('base64')
and it gets perfectly converted into base64 (I know it is working because I am also using that "plugin.file" in .ejs file as a download button something like this,
<a class="btn btn-success btn-sm" download="plugin.zip" href="data:application/zip;base64,<%- plugin %>" role="button">Download</a>
So, now I will be using that "plugin" to send a email to the user, so I am doing something like this just before rendering the ejs page,
if (req.session.email) await sendMail(req.session.email , "Thanks for purchasing" , "Here is your delivery!" , plugin)
res.render('success' , {payment , type: "Payment" , discord , plugin: plugin.file.buffer})
It basically checks if the email of the user is stored in "sessions" i.e. logged in, if yes it sends a email and then renders the success page!
So, the issue is in the email.js file sendMail() function. It is neither sending me the email nor the attachment.
Before showing the code inside that function(), my api keys etc are correct as I am also sending a mail whenever the user creates an account and in that case, everything is working fine and the mail is being sent. But whenever I include the attachment logic, neither the mail nor the attachment is being sent! So, here is my code:-
const { MAILER_API_KEY } = require('../config.json')
const mailer = require('#sendgrid/mail')
mailer.setApiKey(MAILER_API_KEY)
async function sendMail(email , subject , text , plugin) {
mailOptions = {
to: email,
from: 'zoomdev.code#gmail.com',
subject: subject,
text: text
}
// if this if statement is false i.e. plugin is undefined(whenever the user is signing up, he/she doesnt need attachment or stuff. The attachment email is being sent whenever the payment is completed and the file is being sent to the user) it works fine. But sending an attachment doesn't work. The email and attachment doesn't get sent!
if (plugin) mailOptions.attachments = [{
content: plugin.file.buffer,
filename: plugin.file.originalname,
type: 'application/zip', // Here, I have also tried using "application/x-zip-compressed", the type saved in the database and it is the same! :(
disposition: 'attachment'
}]
await mailer.send(mailOptions).then(res => {
console.log(JSON.stringify(res))
return true
}).catch(err => {
console.log(JSON.stringify(err))
return false
})
console.log('Mail sent to ' + email)
}
module.exports = { sendMail }
Whenever sending the attachment email, I am getting this in console,
Executing Payment
Converting to base64
Updating user
// ^ these are something else. Ignore them
// this is the JSON.stringify(... console.log in sendMail function last lines
[{"statusCode":202,"body":"","headers":{"server":"nginx","date":"Fri, 22 Oct 2021 06:57:18 GMT","content-length":"0","connection":"close","x-message-id":"QpxSudqkRGytDU7YFleVgA","access-control-allow-origin":"https://sendgrid.api-docs.io","access-control-allow-methods":"POST","access-control-allow-headers":"Authorization, Content-Type, On-behalf-of, x-sg-elas-acl","access-control-max-age":"600","x-no-cors-reason":"https://sendgrid.com/docs/Classroom/Basics/API/cors.html","strict-transport-security":"max-age=600; includeSubDomains"}},""]
Mail sent to <my email , I have edited this part for privacy, but it correctly logs the email>
Note:-
I am using express#^4.17.1
#sendgrid/mail#^7.4.7
I have checked spam folder and everything
Twilio SendGrid developer evangelist here.
Using a Gmail address as your from address is not a good way to get your emails delivered. Doing so means you are spoofing an email address, even if it is your email address.
When you are spoofing an email address like that, the email server is unable to prove that it has permission to send emails for that address. SPF and DKIM are methods you can use to prove that you control the domain the email is coming from, but when you use a Gmail address (or any other mailbox provider) then you will appear to be spoofing and receiving mailboxes may choose to discard your emails or land them in the spam inbox.
You may have managed to send and receive your account creation emails with this method, but mailbox providers will be a lot more restrictive when it comes to receiving emails with attached zip files. The whole thing appears suspicious and the mailbox will likely reject it, send it spam, or silently delete it.
The advice here is just don't send emails from a domain that you don't control. What you should do is get a domain that you want to send emails from, set up domain authentication for that domain and you will have a much better chance of landing your emails in your users' inboxes than by spoofing Gmail.

Should I sanitize a text from a contact form before sending it to my email?

I have a contact form on a React app. When the user sends the message, it hits a /contact route on my node server. This route calls a MailService, that dispatches the text to my own gmail address.
It works, but what if someone writes shady scripts such as <iframe onLoad="do-nasty-stuff"> instead of a regular message? Will the text be safe by nature because of email providers (it would be pure html or text after all) or should I sanitize it before sending it to me?
If I must sanitize the text, what is the best way to do it in node/express?
The code looks like this:
export class MailControler {
static contact({ email, topic, message }: ContactForm) {
return transporter.sendMail({
from: email,
to: myemail,
subject: topic,
html: message, // TODO: SANITIZE MESSAGE ?
});
}
}

Communication between client and server in Angular 2+

I am using NodeMailer for mail service. I have to get an email address from a field in client side and send that value to app.js where my nodemailer code resides.
client side
ngOnInit() {
this.forgotForm = this.formBuilder.group({
email: this.email,
});
}
sendmail() {
}
app.js, Nodemailer code (I have to get email id for to address here)
let mailOptions = {
from: 'xyz#gmail.com',
to: '',
subject: 'Test Mailer',
text: 'I am testing Nodemailer to send email.',
};
You Should Consider Looking/ Learning Angular and then going into forms . and then into http modules which will help you post data to services
This is a gist not the actual answer
There are a lots of ways to get this done , using normal inputs and getting data from that input using button control or using Forms[the best approach] as you might have other details to send as well.
There are two kind of froms in Angular Template Driven or Reactive Forms.
After getting the details in your form you will need to post it to a Rest service i am guessing. For that you will need to look at Angular Http Client Module
Please look at those links for more detailed Info on them.
You need to use services in angular in order to do this. in terminal set the path to a folder where you want create service, and then use the command ng generate service <service_name> . This will create a file service_name.service.ts. You can refer https://codecraft.tv/courses/angular/http/overview/ or https://angular.io/tutorial/toh-pt4 for more details.
You can use APIs along with http methods get, post, put, delete etc. to complete your task.
In respective component.ts file create a variable email like:
email =string;
In the html file bind the input field with ngModel as:
[(ngModel)]="email"
Then make a function in service.ts that accepts email as arguments
endMail(email) {
//make api call using http method(say post)
// supply email
let url = <APIURL>
return http.post(url, {email: email});
}
Again in component.ts import this service and instantiate in constructor and use a method to call service

Twilio is not sending creds in headers when specifying username:password format in the URL

I'm currently developing my app and I'm at the stage where I can start testing messages from Twilio. I configured my server on digital ocean with a public facing IP address and my Nodejs app is listening to calls from Twilio.
I also configured my phone number's message "request url" to "http://username:password#198.xxx.xxx.xxx/messages" with "HTTP POST".
When I debug the headers, I don't see the "authorization" headers. I'm I missing something here?
Any help is much appreciated!
Below is the code.
var headerValues = bag.req.headers.authorization.split(' ');
console.log(bag.req.headers);
var scheme = headerValues[0];
if (scheme === 'Basic') {
var credentials = headerValues[1];
var decoded = new Buffer(credentials, 'base64').toString().split(':');
bag.req.creds = {
userName: decoded[0],
password: decoded[1],
authType: 'basic'
}
}
I use the same setup as you do in several call centers I have built.
If you are using a proxy setup which requires username:password# before the IP address then your issue is likely with that proxy if you can access the code by going directly to the actual server ip address as I note below. However, you did not mention using a proxy just using a digital ocean droplet so I am responding assuming you do not have a proxy setup.
So if you do have a proxy setup make sure you can access the IP address of the server directly first.
Also if those are just extra variables you need to pass over you may be better off appending them after the IP address
for instance xxx.xxx.xxx.xxx/username/password
Then get them with req.params
for instance (and yes this will work with post data since its merely part of the URL and not an actual get command post)
router.post('/sms/:username/:password'), function(req, res, next){
username = req.params.username;
}
First you would not want to direct your request URL at "http://username:password#198.xxx.xxx.xxx/messages" with "HTTP POST".
If you do not have a domain directed at your IP address yet you want your request URL to be
https://198.xxx.xxx.xxx/inbound/sms
{Replacing /inbound/sms with whatever route you are using}
Then at the top of your route (I am using express so my setup may look different than your)
I have the node.js twilio library
, twilio = require('twilio')
, capability = new twilio.Capability(sid, auth)
, client = require('twilio')(sid, auth)
Then here is an example of my /sms route
router.post('/sms', function(req, res, next){
var sid = req.body.SmsSid;
var from = req.body.From;
var to = req.body.To;
var date = Date();
var body = req.body.Body;
if(req.body.NumMedia > 0){
code to handle MMS
}
Code to handle SMS data
res.send("Completed");
});
I ran into this this week and discovered that behavior surrounding Basic Auth in the URL is very cloudy. For one thing, it appears to be deprecated from the URI spec as it pertains to HTTP:
...
3.2.1. User Information
...
Use of the format "user:password" in the userinfo field is deprecated.
...7.5. Sensitive Information
URI producers should not provide a URI that contains a username or password that is intended to be secret. URIs are frequently displayed by browsers, stored in clear text bookmarks, and logged by user agent history and intermediary applications (proxies). A password appearing within the userinfo component is deprecated and should be considered an error (or simply ignored) except in those rare cases where the 'password' parameter is intended to be public.
...
Because of this, both Firefox and Chrome appear to just strip it out and ignore it. Curl, however, seems to convert it to a valid Authorization header.
Whatever the case, I believe this functionality is actually the responsibility of the HTTP user agent, and it appears that Twilio's user agent is not doing its job. Thus, there is no way to make basic auth work.
However, it appears Twilio's preferred method of auth is to simply sign the request using your account's secret auth key, which you can then verify when handling the request. See here.
On researching the raw NodeJS Request and IncomingMessage classes, there appears to be no way to get at the full, raw URL to compensate for Twilio's non-conformity. I believe this is because the actual data of an HTTP request doesn't contain the full URL.
My understanding is that it's actually the HTTP user agent that's responsible for extracting and formatting the auth info from the URL. That is, a conformant HTTP user agent should parse the URL itself, using the hostname and port portion to find the right door on the right machine, the protocol portion to establish the connection with the listener, the verb combined with the URL's path portion to indicate what functionality to activate, and presumably it is then responsible for converting the auth section of the URL to an official HTTP Authorization header.
Absent that work by the user agent, there is no way to get the auth data into your system.
(This is my current understanding, although it may not be totally accurate. Others, feel free to comment or correct.)

View order schema does not appear using nodemailer but google app script

I have been trying to create an Google order Schema markup for our orders. However, the html template that I generate works when I run it using the google App Script Test
Code.gs file in Google App script
function testSchemas() {
var htmlBody = HtmlService.createHtmlOutputFromFile('template_html').getContent();
MailApp.sendEmail({
// to: Session.getActiveUser().getEmail(),
to:'MY GMAIL EMAIL',
subject: 'Test Actions in the Inbox - ' + new Date(),
htmlBody: htmlBody,
});
}
But when I use the same html template in nodemailer and run the nodemailer with the same gmail credentials using the Gmail Service, I do not find the
"View order" section.
I am aware that to: and from: addresses need to be same for testing schemas and I have the same to and from address.
My nodemailer config looks something like:
var smtpTransport = nodemailer.createTransport("SMTP",{
service: "Gmail",
auth: {
user: "GMAIL EMAIL",
pass: "PASSWORD"
}
});
smtpTransport.sendMail(mailOptions,function(err,response){console.log('Done');});
Google says your email must be SPF/DKIM enabled in order to stop phishing attacks but when I am using the Gmail service, it must not be the case.
Can anybody tell me what might be the reason for this and the workaround of how could I test it using node mailer before I raise a request to whitelist my IpP to Google.
Also, can we make Google orders to appear as Google card in Google Now.

Resources