Meteor login through different server - meteor

I want to let my meteor users login through my react-native app.
I have one website built by Meteor/reactjs and the other is an App using android react-native and they both share the same Mongo database.
My meteor website uses bcrypt (meteor accounts-password), and my react-native app where I tried to use SHA256 and bcrypt so when I log in through my react-native app which is connected to the database, the hashed passwords do not match and I get an error.
I'm just getting really confused as to how to hash my react-native password to get it to the match the meteor users' hashed password. Any help would be great, cheers.
This is the front end
sendAjax = () => {
const m = encodeURIComponent(this.state.email);
const p = encodeURIComponent(this.state.password);
const hashDigest = sha256(p);
const requestBody = `email=${m}&password=${hashDigest}&mphone`;
//POST
fetch("http://**************/users/auth", {
method: "POST",
mode: "cors",
headers: {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
},
body: requestBody
}).then(function (res, next) {
console.log("fetch request ", JSON.stringify(res.ok));
if(res.ok){
res.json().then(function (json) {
console.info(json);
console.info(json.verifystate);
if(json.verifystate){
Alert.alert("Login success");
Actions.leaderBoard();
}else{
Alert.alert("Login fail, please try again");
}
});
}else{
Alert.alert('Noted','request failed',[{text: 'confirm', onPress: () => console.log('OK Pressed!')},]);
next();
}
})
.catch(function (e) {
console.log("fetch fail");
Alert.alert('Noted','system error',[{text: 'confirm', onPress: () => console.log('OK Pressed!')},]);
});
}
This is my backend
app.post('/users/auth', function(req, res) {
loginData(db, req.body.email, req.body.password, function(result){
if(result == 1){
console.log("find the result!");
res.send({"verifystate":true});
}else{
console.log('cannot find it');
}
});
});
......
var loginData = function(db, email, myPlaintextPassword, mphone, callback){
var collectionUser = db.collection('users');
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(myPlaintextPassword, salt, function(err, hash) {
var queryStr = {"emails.address": email, "services.password.bcrypt": hash};
collectionUser.count(queryStr, function(err, result) {
if(err)
{
console.log('Error2:'+ err);
}
callback(result);
});
});
});
};

Related

How to get logged user in vuejs

I made a jwt authetication using asp.net core and vuejs
this is my auth controller :
[Route("Login")]
[HttpPost]
public IActionResult Login(LoginArgument loginArgument)
{
var user = _userService.GetByEmail(loginArgument.Email);
if (user == null) return BadRequest(error: new { message = "Invalid credential : verify email" });
if (!BC.BCrypt.Verify(text: loginArgument.Password, hash: user.Password))
{
return BadRequest(error: new { message = "Invalid credential : verify password" });
}
var jwt= _jwtService.Generate(user.Id);
Response.Cookies.Append(key: "jwt", value: jwt, new Microsoft.AspNetCore.Http.CookieOptions
{
HttpOnly=false,
SameSite=Microsoft.AspNetCore.Http.SameSiteMode.None
}) ;
return Ok(user);
}
[Route("User")]
[HttpGet]
public IActionResult User()
{
try
{
var jwt = Request.Cookies["jwt"];
var token = _jwtService.Verify(jwt);
int userId = int.Parse(token.Issuer);
var user = _userService.GetById(userId);
return Ok(user);
}
catch (Exception)
{
return Unauthorized();
}
}
and this is the login in vue
<script lang="ts">
import { reactive } from 'vue';
import { useRouter } from "vue-router";
export default {
name: "Login",
setup() {
const data = reactive({
email: '',
password: ''
});
const router = useRouter();
const submit = async () => {
await fetch('https://localhost:44391/api/Auth/Login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify(data)
});
await router.push('/Countries');
}
return {
data,
submit
}
},
}
the login part is working in front and back sides perfectly and i can see the cookies
the problem is when i try to get the logged user. in back side i can get it successfully but in front it says that no user is logged
here is the loggedUser vue
<script lang="ts">
import { onMounted, ref } from 'vue';
export default {
name: "LoggedUser",
setup() {
const message = ref('You are not logged in!');
onMounted(async () => {
const response = await fetch('https://localhost:44391/api/Auth/User', {
headers: { 'Content-Type': 'application/json' },
credentials: 'include'
});
const content = await response.json();
message.value = `hi ${content.name}`;
});
return {
message
}
}
}
Here is the errors i got when i inspect the page :
this issues appear the moment of login
1- Mark cross-site cookies as Secure to allow setting them in cross-site contexts
2- Migrate entirely to HTTPS to have cookies sent to same-site subresources
this one appears when i call loggedUser in front even so it works in the back side
{type: "https://tools.ietf.org/html/rfc7235#section-3.1", title: "Unauthorized", status:
401,…}
status: 401
title: "Unauthorized"
traceId: "00-b4a9f6fee8dff6439952ded0bb50005d-43c9aee84c454b40-00"
type: "https://tools.ietf.org/html/rfc7235#section-3.1"
You need to send the access token in the request headers
Example:
let token = '???'
const response = await post('localhost/api/auth/user', {
headers: {
'Content-Type': 'application/json'
'Authorization' : 'Bearer '+ token
}
});

How to use next-auth using ldap and prisma

i am using next-auth with ldap to authenticate user name and password. i am able to log/authenticate the user using username and password. but when i can't create user using prisma as await is not allowed inside promise.
this is my [...next-auth].js
`
const ldap = require("ldapjs");
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { PrismaClient } from "#prisma/client";
const url = `ldap://${process.env.LDAP_SERVER}`;
const prisma = new PrismaClient();
export default NextAuth({
providers: [
CredentialsProvider({
name: "LDAP",
credentials: {
username: { label: "DN", type: "text", placeholder: "" },
password: { label: "Password", type: "password" },
},
authorize: async (credentials, req) => {
// You might want to pull this call out so we're not making a new LDAP client on every login attemp
const client = ldap.createClient({
url: url,
});
return new Promise((resolve, reject) => {
client.bind(
`${credentials.username}#${process.env.LDAP_DOMAIN}`,
credentials.password,
(error) => {
if (error) {
console.log("Wrong email or password.");
reject("Wrong email or password.");
} else {
console.log("Successfully Logged In");
resolve({
username: credentials.username,
password: credentials.password,
});
}
const filter = `(sAMAccountName=${credentials.username})`;
client.search(
process.env.LDAP_BASE_DN,
{
filter,
scope: "sub",
attributes: [
"mail",
"employeeid",
"title",
"name",
"division",
"department",
"section",
],
},
(err, results) => {
if (err) {
reject(`User ${username} LDAP search error`);
}
const entries = [];
results.on("searchEntry", (entry) => {
entries.push(entry.object);
});
results.on("error", (err) => {
reject("LDAP SEARCH error");
});
results.on("end", (result) => {
if (entries.length == 0) {
reject("Something went wrong. Please try again. (AD)");
}
console.log({ entries });
const searchResult = JSON.stringify(entries[0]);
const adEmployee = JSON.parse(searchResult);
const empId = adEmployee?.employeeID;
const name = adEmployee.name;
console.log(empId);
const newUser= await prisma.user.findUnique({
where:{
oracleId:oracleId
}
})
if(!newUser){
await prisma.user.create({
data:{
oracleId:empId,
fullName:name
}
})
}
});
}
);
}
);
});
},
}),
],
pages: {
signIn: "/auth/sign-in",
},
callbacks: {
jwt: async ({ token, user }) => {
if (user) {
token.username = user.username;
token.password = user.password;
}
return token;
},
session: async ({ session, token }) => {
if (token) {
session.id = token.id;
session.username = token.username;
}
// console.log(token);
return session;
},
},
debug: process.env.NODE_ENV === "development",
secret: process.env.NEXTAUTH_SECRET,
jwt: {
secret: process.env.NEXTAUTH_SECRET,
encryption: true,
},
});
`
await is not allowed inside promise, where should i call prisma.
Thanks
For this u need to use API endpoint (as prisma is used on server side and cannot be used on client side especially when you pass db url from env also not shown on frontend), your create for example /api/register where:
import { PrismaClient } from '#prisma/client';
import dotenv from 'dotenv'
dotenv.config();
const prisma = new PrismaClient();
const Handler = async (
req,
res
) => {
await prisma.$connect()
const users = await prisma.user.findMany()
//check if user u add is already in db
//if not then
try {
savedUser = await prisma.user.create({ data: new_user });
await prisma.$disconnect()
} catch (error: any) {
await prisma.$disconnect()
// show db error
return res.status(501).json({message: error.message})
}
res.status(200).json({ message: 'User added to db ' + savedUser.name });
}
this is just a simple explanation of what you need to do to make it work, you may add some safety:
const { username, password } = req.body
if (req.method !== 'POST') {
return res.status(405).json({ message: 'Method not allowed' });
}
if (!username || !password) {
return res.status(400).json({ message: 'Username and password are required' });
}
then u call api endpoint:
const response = await axios.post(
LOGIN_URL,
JSON.stringify({ username, password }),
{
headers: { 'Content-Type': 'application/json' },
withCredentials: true
}
)
where LOGIN_URL could be /api/register

FCM very slow and unreliable when sending to a group of recipients through Cloud Function

I have the following Function that:
Listens for document (text message) creation
Grab IDs of members of a group chat
Get the FCM Tokens for each member
With a for-loop, send messages to group members
exports.sendChatMessage = functions.firestore
.document("chats/{mealID}/messages/{messageID}")
.onCreate((snap, context) => {
const data = snap.data();
const mealID = context.params.mealID;
const senderID = data.senderID;
const senderName = data.senderName;
const messageContent = data.content;
var docRef = db.collection("chats").doc(mealID);
docRef
.get()
.then((doc) => {
if (doc.exists) {
const docData = doc.data();
const mealName = docData.name;
const userStatus = docData.userStatus;
var users = docData.to;
var eligibleUsers = users.filter(
(user) => userStatus[user] == "accepted"
);
eligibleUsers.push(docData.from);
// get fcmTokens from eligibleUsers and send the messagme
db.collection("users")
.where("uid", "in", eligibleUsers)
.get()
.then((snapshot) => {
var fcmTokens = [];
var thumbnailPicURL = "";
// get thumbnailpic of the sender and collect fcmTokens
snapshot.forEach((doc) => {
if (doc.data().uid == senderID) {
thumbnailPicURL =
doc.data().thumbnailPicURL == null
? "https://i.imgur.com/8wSudUk.png"
: doc.data().thumbnailPicURL;
} else {
fcmTokens.push(doc.data().fcmToken);
}
});
// send the message fcmTokens
fcmTokens.forEach((token) => {
if (token != "") {
const fcmMessage = {
message: {
token: token,
notification: {
title: mealName,
body: senderName + ": " + messageContent,
image: thumbnailPicURL,
},
apns: {
payload: {
aps: {
category: "MESSAGE_RECEIVED",
},
MEAL_ID: mealID,
},
},
},
};
tokenManger.sendFcmMessage(fcmMessage);
}
});
return true;
});
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
return false;
}
})
.catch((error) => {
console.log("Error getting document:", error);
return false;
});
return true;
});
My send function comes from a helper file that uses the HTTP V1 protocol to build the send-request:
const { google } = require("googleapis");
const https = require("https");
const MESSAGING_SCOPE = "https://www.googleapis.com/auth/firebase.messaging";
const SCOPES = [MESSAGING_SCOPE];
const PROJECT_ID = MY_PROJECT_ID;
const HOST = "fcm.googleapis.com";
const PATH = "/v1/projects/" + PROJECT_ID + "/messages:send";
exports.getAccessToken = () => {
return new Promise(function (resolve, reject) {
const key = require("./service-account.json");
var jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
SCOPES,
null
);
jwtClient.authorize(function (err, tokens) {
if (err) {
reject(err);
return;
}
resolve(tokens.access_token);
});
});
};
//send message
exports.sendFcmMessage = (fcmMessage) => {
this.getAccessToken().then(function (accessToken) {
var options = {
hostname: HOST,
path: PATH,
method: "POST",
headers: {
Authorization: "Bearer " + accessToken,
},
// … plus the body of your notification or data message
};
var request = https.request(options, function (resp) {
resp.setEncoding("utf8");
resp.on("data", function (data) {
console.log("Message sent to Firebase for delivery, response:");
console.log(data);
});
});
request.on("error", function (err) {
console.log("Unable to send message to Firebase");
console.log(err);
});
request.write(JSON.stringify(fcmMessage));
request.end();
});
};
It worked all fine in the emulator but once deployed, there're significant delays (~3 mins):
I also noticed that the console says the cloud function finishes execution BEFORE sendFcmMessage logs success messages.
I did some research online, it appears that it might have something to do with the usage of Promise but I wasn't sure if that's the sole reason or it has something to do with my for-loop.
The Problem
To summarize the issue, you are creating "floating promises" or starting other asynchronous tasks (like in sendFcmMessage) where you aren't returning a promise because they use callbacks instead.
In a deployed function, as soon as the function returns its result or the Promise chain resolves, all further actions should be treated as if they will never be executed as documented here. An "inactive" function might be terminated at any time, is severely throttled and any network calls you make (like setting data in database or calling out to FCM) may never be executed.
An indicator that you haven't properly chained the promises is when you see the function completion log message ("Function execution took...") before other messages you are logging. When you see this, you need to look at the code you are running and confirm whether you have any "floating promises" or are using callback-based APIs. Once you have changed the callback-based APIs to use promises and then made sure they are all chained together properly, you should see a significant boost in performance.
The fixes
Sending the message data to FCM
In your tokenManger file, getAccessToken() could be reworked slightly and sendFcmMessage should be converted to return a Promise:
exports.getAccessToken = () => {
return new Promise(function (resolve, reject) {
const key = require("./service-account.json");
const jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
SCOPES,
null
);
jwtClient.authorize(
(err, tokens) => err ? reject(err) : resolve(tokens.access_token)
);
});
};
//send message
exports.sendFcmMessage = (fcmMessage) => {
// CHANGED: return the Promise
return this.getAccessToken().then(function (accessToken) {
const options = {
hostname: HOST,
path: PATH,
method: "POST",
headers: {
Authorization: "Bearer " + accessToken,
},
// … plus the body of your notification or data message
};
// CHANGED: convert to Promise:
return new Promise((resolve, reject) => {
const request = https.request(options, (resp) => {
resp.setEncoding("utf8");
resp.on("data", resolve);
resp.on("error", reject);
});
request.on("error", reject);
request.write(JSON.stringify(fcmMessage));
request.end();
});
});
};
However, the above code was built for googleapis ^52.1.0 and google-auth-library ^6.0.3. The modern versions of these modules are v92.0.0 and v7.11.0 respectively. This means you should really update the code to use these later versions like so:
// Import JWT module directly
const { JWT } = require('google-auth-library');
// FIREBASE_CONFIG is a JSON string available in Cloud Functions
const PROJECT_ID = JSON.parse(process.env.FIREBASE_CONFIG).projectId;
const FCM_ENDPOINT = `https://fcm.googleapis.com/v1/projects/${PROJECT_ID}/messages:send`;
const FCM_SCOPES = ["https://www.googleapis.com/auth/firebase.messaging"];
exports.sendFcmMessage = (fcmMessage) => {
const key = require("./service-account.json"); // consider moving outside of function (so it throws an error during deployment if its missing)
const client = new JWT({
email: key.client_email,
key: key.private_key,
scopes: FCM_SCOPES
});
return client.request({ // <-- this uses `gaxios`, Google's fork of `axios` built for Promise-based APIs
url: FCM_ENDPOINT,
method: "POST",
data: fcmMessage
});
}
Better yet, just use the messaging APIs provided by the Firebase Admin SDKs that handle the details for you. Just feed it the message and tokens as needed.
import { initializeApp } from "firebase-admin/app";
import { getMessaging } from "firebase-admin/messaging";
initializeApp(); // initializes using default credentials provided by Cloud Functions
const fcm = getMessaging();
fcm.send(message) // send to one (uses the given token)
fcm.sendAll(messagesArr) // send to many at once (each message uses the given token)
fcm.sendMulticast(message) // send to many at once (uses a `tokens` array instead of `token`)
The Cloud Function
Updating the main Cloud Function, you'd get:
exports.sendChatMessage = functions.firestore
.document("chats/{mealID}/messages/{messageID}")
.onCreate((snap, context) => {
const mealID = context.params.mealID;
const { senderID, senderName, content: messageContent } = snap.data();
const docRef = db.collection("chats").doc(mealID);
/* --> */ return docRef
.get()
.then((doc) => {
if (!doc.exists) { // CHANGED: Fail fast and avoid else statements
console.log(`Could not find "chat:${mealID}"!`);
return false;
}
const { userStatus, to: users, name: mealName, from: fromUser } = doc.data();
const eligibleUsers = users.filter(
(user) => userStatus[user] == "accepted"
);
eligibleUsers.push(fromUser);
// get fcmTokens from eligibleUsers and send the message
/* --> */ return db.collection("users")
.where("uid", "in", eligibleUsers) // WARNING: This will only work for up to 10 users! You'll need to break it up into chunks of 10 if there are more.
.get()
.then(async (snapshot) => {
const fcmTokens = [];
let thumbnailPicURL = "";
// get thumbnailpic of the sender and collect fcmTokens
snapshot.forEach((doc) => {
if (doc.get("uid") == senderID) {
thumbnailPicURL = doc.get("thumbnailPicURL"); // update with given thumbnail pic
} else {
fcmTokens.push(doc.get("fcmToken"));
}
});
const baseMessage = {
notification: {
title: mealName,
body: senderName + ": " + messageContent,
image: thumbnailPicURL || "https://i.imgur.com/8wSudUk.png", // CHANGED: specified fallback image here
},
apns: {
payload: {
aps: {
category: "MESSAGE_RECEIVED",
},
MEAL_ID: mealID,
},
}
}
// log error if fcmTokens empty?
// ----- OPTION 1 -----
// send the message to each fcmToken
const messagePromises = fcmTokens.map((token) => {
if (!token) // handle "" and undefined
return; // skip
/* --> */ return tokenManger
.sendFcmMessage({
message: { ...baseMessage, token }
})
.catch((err) => { // catch the error here, so as many notifications are sent out as possible
console.error(`Failed to send message to "fcm:${token}"`, err);
})
});
await Promise.all(messagePromises); // wait for all messages to be sent out
// --------------------
// ----- OPTION 2 -----
// send the message to each fcmToken
await getMessaging().sendAll(
fcmTokens.map((token) => ({ ...baseMessage, token }))
);
// --------------------
return true;
})
.catch((error) => {
console.log("Error sending messages:", error);
return false;
});
})
.catch((error) => {
console.log("Error getting document:", error);
return false;
});
});
I found out that the culprit is my queries to db. Like #samthecodingman commented, I was creating floating Promises.
Originally, I have codes like:
db.collection("users")
.where("uid", "in", eligibleUsers)
.get()
.then((snapshot) => {...}
All I needed to do is to return that call:
return db.collection("users")
.where("uid", "in", eligibleUsers)
.get()
.then((snapshot) => {...}
Although it's still not instant delivery, it's much faster now.

Using IBM Watson Text-to-Speech with Firebase Cloud Functions?

I'm trying to use set up a Firebase Cloud Function to access IBM Watson Text-to-Speech. The problem is writing the returned audiofile to my Firestore database.
This test to return the list of voices worked, logging the response to the Functions log:
exports.test = functions.firestore.document('IBM_Watson_Token/Test_Value').onUpdate((change, context) => {
var textToSpeech = new TextToSpeechV1({
username: 'groucho',
password: 'swordfish'
});
return textToSpeech.listVoices(null, function(error, voices) {
if (error) {
console.log(error);
} else {
console.log(JSON.stringify(voices, null, 2));
}
});
});
Here is the documentation example Node code for returning an audiofile and writing it to the server:
var TextToSpeechV1 = require('watson-developer-cloud/text-to-speech/v1');
var fs = require('fs');
var textToSpeech = new TextToSpeechV1({
username: '{username}',
password: '{password}'
});
var synthesizeParams = {
text: 'Hello world',
accept: 'audio/wav',
voice: 'en-US_AllisonVoice'
};
// Pipe the synthesized text to a file.
textToSpeech.synthesize(synthesizeParams).on('error', function(error) {
console.log(error);
}).pipe(fs.createWriteStream('hello_world.wav'));
Firebase doesn't allow writing files to the server using fs, you have to write to a Firestore database. I changed the last line of the example code to write to Firestore, using a promise:
exports.test = functions.firestore.document('IBM_Watson_Token/Test_Value').onUpdate((change, context) => {
var textToSpeech = new TextToSpeechV1({
username: 'groucho',
password: 'swordfish'
});
var synthesizeParams = {
text: 'Hello world',
accept: 'audio/wav',
voice: 'en-US_AllisonVoice'
};
return textToSpeech.synthesize(synthesizeParams).on('error', function(error) {
console.log(error);
}).then(function (audiofile) {
admin.firestore().collection('IBM_Watson_Token').doc('hello_world').set({
'audiofile': audiofile
})
})
.catch(function (error) {
console.log(error);
});
});
The error message was
TypeError: textToSpeech.synthesize(...).on(...).then is not a function
How do I save the audiofile that comes back from Watson to Firestore?
That would be because the synthesize method is not returning a promise. You will need to use a callback construct that looks like
textToSpeech.synthesize(params, function (err, body, response) {
if (err) {
...
} else {
// body is the audio
...
}
});

Cloud function return RequestError: Error: socket hang up

I have use Cloud function connect with onesignal service which will send notification to user. After test function locally, it's work perfectly but after deploying to the cloud function it return me an error "RequestError: Error: read ECONNRESET" which I thick the cloud function reset the connection
Here is what my code look like
exports.sendNotification = functions
.pubsub
.topic('cron-notification')
.onPublish(async (message) => {
const databaseRef = admin.database();
// Query all user from realtime db
const snapshotsUser = await databaseRef
.ref(`user`)
.orderByKey()
.once("value");
// Check if user exist
if (snapshotsUser) {
//Get the user key
const user_object_key = Object.keys(snapshotsUser.val());
// send notification for each user
user_object_key.map(async (user_id) => {
// query something
const snapshotsUser = await databaseRef
.ref(`record/user_id`)
.orderByKey()
.once("value");
const message = {
"app_id": "xxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",
"filters": [
{"field": "tag", "key": "user_id", "value": user_id}
],
"headings": {"en": `Hello World`},
"contents": {"en": `Hello`}
}
sendNotification(message);
})
}
});
function sendNotification(message) {
const headers = {
"Content-Type": "application/json; charset=utf-8",
"Authorization": "Basic XXXXXXXXXXXXXXXXXXXXXXXXXXX"
};
// Use onesignal for send notification
const options = {
uri: "https://onesignal.com/api/v1/notifications",
headers: headers,
method: 'POST',
json: true,
body: message,
resolveWithFullResponse: true,
}
return request(options).then(response => {
if (response.statusCode >= 400) {
throw new Error(`HTTP Error: ${response.statusCode}`);
} else {
console.log(response.body)
}
}).catch(error => {
console.log(error);
})
}
Can anyone give suggestion for me?
According to the Node.js documentation ‘ECONNRESET’ error occurs when a connection is forcibly closed by peer. This results in loss of connection on the remote socket due to timeout or reboot. Since you mentioned the code is working locally and the error occurs after it is deployed, here is an answer that says the possible solution is to increase the number of cores so the requests can be serviced faster. Also, it might be useful to read the GitHub discussion on socket hang up error.
Just for people who face the same problem with me, I just notice that I did not return anything in the function. The cloud function will reset the function if it did not return any thing back. So from the code above should be like this and everything work fine.
exports.sendNotification = functions.pubsub.topic('cron-notification').onPublish(async (message) => {
const databaseRef = admin.database();
// Query all user from realtime db
const snapshotsUser = await databaseRef
.ref(`user`)
.orderByKey()
.once("value");
// Check if user exist
if (snapshotsUser) {
//Get the user key
const user_object_key = Object.keys(snapshotsUser.val());
// send notification for each user
return Promise.all([ user_object_key.map(async (user_id) => {
// query something
const snapshotsUser = await databaseRef
.ref(`record/user_id`)
.orderByKey()
.once("value");
const message = {
"app_id": "xxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",
"filters": [
{"field": "tag", "key": "user_id", "value": user_id}
],
"headings": {"en": `Hello World`},
"contents": {"en": `Hello`}
}
sendNotification(message);
})])}});
function sendNotification(message) {
const headers = {
"Content-Type": "application/json; charset=utf-8",
"Authorization": "Basic XXXXXXXXXXXXXXXXXXXXXXXXXXX"
};
// Use onesignal for send notification
const options = {
uri: "https://onesignal.com/api/v1/notifications",
headers: headers,
method: 'POST',
json: true,
body: message,
resolveWithFullResponse: true,
}
return request(options).then(response => {
if (response.statusCode >= 400) {
throw new Error(`HTTP Error: ${response.statusCode}`);
} else {
console.log(response.body)
}
}).catch(error => {
console.log(error);
})}

Resources