I'm using Joi to validate some data from user. I'm using it with module like this:
const Joi = require('joi')
// User validation rules
module.exports = {
create: {
body: {
email: Joi.string().email().required(),
password: Joi.string().min(6).max(128).required(),
name: Joi.string().max(128).required()
}
},
update: {
body: {
password: Joi.string().min(6).max(128).required(),
name: Joi.string().max(128).required()
}
}
}
and then in router I'm passing it as middleware:
router.post('/register', validator(create), userController.register)
For update I want to create custom validator with code like this:
const json = {
"email":"aa#aa.pl",
"password":"someNewPass",
"name":"John Smith",
"activationKey":"123123",
"active":false,
"resetPasswordKey":"123123"
}
const forbiddenFields = ["email", "activationKey", "active", "resetPasswordKey"];
const validate = (json, forbidden) => {
for(let i = 0; i < forbidden.length; i++) {
if(json.hasOwnProperty(forbidden[i])) {
return false;
}
}
return true;
}
const isValid = validate(json, forbiddenFields)
console.log('is json valid? ', isValid)
I found extend method in Joi API but example is so confusing that I can not handle to create custom validation with my code.
You may want to use forbidden keys.
const input = {
email: 'example#example.com',
activationKey: 123
};
const schema = {
email: Joi.string().email(),
activationKey: Joi.any().forbidden()
};
const result = Joi.validate(input, schema);
if (result.error) {
console.log(result.error.details)
}
<script src="https://cdn.jsdelivr.net/npm/joi-browser#13.4.0/dist/joi-browser.min.js"></script>
Related
So, I have built this way of auth with firebase and graphql using mongo database, the problem is that everything is working, instead trying to login, its the same way of register but sometimes the method works and some times I get apollo client error, which I don't know why.
Here is my code to auth with Firebase and then check if the user exits and call the method and then the oposite.
import { FirebaseAuth } from "../config/Firebase";
import { GoogleAuthProvider, signInWithPopup } from "firebase/auth";
import { Notifier } from "../utils";
import { USER_AUTH_ERROR } from "../config/Responders";
const Google = async (Register, Login, dispatch) => {
var Provider = new GoogleAuthProvider();
const data = await signInWithPopup(FirebaseAuth, Provider);
try {
if (data) {
const user = data.user;
const creationTime = user.metadata.creationTime;
const lastSignInTime = user.metadata.lastSignInTime;
if (creationTime === lastSignInTime) {
const name = user.displayName.split(" ");
const firstName = name[0] || "";
const lastName = name[1] || "";
const config = {
variables: {
createUserInput: {
Name: firstName,
Surname: lastName,
Email: user.email,
Avatar: user.photoURL || null,
Uid: user.uid,
},
},
};
Register(config);
}
else {
const config = {
variables: {
uid: user.uid,
},
};
Login(config);
}
}
else Notifier(dispatch, USER_AUTH_ERROR, `error`);
} catch (error) {
Notifier(dispatch, USER_AUTH_ERROR, `error`);
}
};
export
default Google;
While here is the place where I manage the functions:
const [Register, { data: registerData }] = useMutation(REGISTER);
const [Login, { data: loginData }] = useLazyQuery(AUTH);
const Auther = () => Google(Register, Login, dispatch);
useEffect(() => {
if (!account.Auth) {
if (registerData?.hasOwnProperty("UserRegister")) {
dispatch(Authenticate(registerData.UserRegister));
}
}
}, [registerData]);
useEffect(() => {
if (!account.Auth) {
if (loginData?.hasOwnProperty("UserAuth")) {
dispatch(Authenticate(loginData.UserAuth));
}
}
}, [loginData]);
Here is the error I get:
I'm using React Native
I'm staying on the same issue over and over again.
This code uses axios. I don't know why it keeps returning undefined. I wrote all of my twilio ids correctly.
I used serverless twilio it worked but I didn't know how I could change it my way.
If I can't use this code anymore, please let me know if there is another good way.
I don't know how to use node.js.
I'd appreciate your help.
Here is the code.
Fetch.js
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.default = void 0;
var _querystring = _interopRequireDefault(require('querystring'));
var _axios = _interopRequireDefault(require('axios'));
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
class Fetch {
constructor({twilioServiceSid, twilioAccountSid, twilioAuthToken}) {
const fetch = _axios.default.create({
baseURL: `https://verify.twilio.com/v2/Services/${twilioServiceSid}`,
auth: {
username: twilioAccountSid,
password: twilioAuthToken,
},
});
this.fetch = fetch;
}
async post({path, payload}) {
try {
const obj = {
To: payload.phone,
Channel: 'sms',
};
if ('code' in payload) {
obj['Code'] = payload.code;
}
const {status, data} = await this.fetch.request({
method: 'POST',
url: path,
data: _querystring.default.stringify(obj),
});
return {
status,
data,
};
} catch (error) {
return error;
}
}
}
exports.default = Fetch;
Verify.js
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.default = void 0;
var _phone = _interopRequireDefault(require('phone'));
var _fetch = _interopRequireDefault(require('./fetch'));
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
class Serify {
constructor({twilioServiceSid, twilioAccountSid, twilioAuthToken}) {
this.fetch = new _fetch.default({
twilioServiceSid,
twilioAccountSid,
twilioAuthToken,
});
this.twilioAccountSid = twilioAccountSid;
this.twilioAuthToken = twilioAuthToken;
}
async start({phone, country}) {
try {
const number = (0, _phone.default)(phone, country ? country : 'USA');
if (!number) {
throw new Error(
'Invalid phone number. Please provide the country code in an ISO-3166 alpha 3 format.',
);
}
const response = await this.fetch.post({
path: 'Verifications',
payload: {
phone: number,
},
});
return {
code: response.status,
data: response.data,
};
} catch (error) {
return new Error(error);
}
}
async verify({phone, country, code}) {
try {
const number = (0, _phone.default)(phone, country ? country : 'USA');
if (!number) {
throw new Error(
'Invalid phone number. Please provide the country code in an ISO-3166 alpha 3 format.',
);
}
if (code.length <= 3) {
throw new Error('Invalid SMS code.');
}
const response = await this.fetch.post({
path: 'VerificationCheck',
payload: {
phone: number,
code: code.toString(),
},
});
return {
code: response.status,
data: response.data,
};
} catch (error) {
return new Error(error);
}
}
}
exports.default = Serify;
const verify = new Serify({
twilioServiceSid: '',
twilioAccountSid: '',
twilioAuthToken: '',
});
try {
const ss = await verify.start({
phone: '+1456123123',
});
console.log(ss);
} catch (e) {
console.log(e);
}
Twilio developer evangelist here.
I'm not sure which part you are saying is returning undefined. But, there is a bigger issue here.
When building a native application, you cannot embed your Twilio credentials within the app and make API requests direct to Twilio from the application. A malicious user could decompile the application, extract your account credentials and abuse your Twilio account.
You should not make the API request from your application. Instead, you should build a server side proxy that stores your Twilio credentials and makes the API request, which you trigger from the application.
I don't have an example of this for Twilio Verify and React Native, but the theory is the same as sending an SMS from a React application.
If you had managed to implement this using Twilio Serverless, then you should go back to that version. If you have trouble with that, I would ask a new question.
Here I have a file, mail.js, that sends an email
const nodemailer = require('nodemailer')
const mailGun = require('nodemailer-mailgun-transport')
const auth = {
auth: {
api_key: process.env.MAILGUN_API_KEY,
domain: process.env.DOMAIN
}
}
const transporter = nodemailer.createTransport(mailGun(auth))
const mailTo = (name, email) => {
const mailOptions = {
from: 'example#icloud.com',
to: 'cm#example.com',
subject: 'Welcome!',
text: `Hey, ${name}! Thanks for joining Task Manager!`
}
transporter.sendMail(mailOptions)
}
module.exports = mailTo
I am trying to do Jest tests and I need to mock the nodemailer and mailGun functions so I don't get an email every time I run a test. So I made a __mocks__ folder and put my 2 mock modules in it at __mocks__/nodemailer.js and __mocks__/nodemailer-mailgun-transport.js. Here are those files
//nodemailer.js
module.exports = {
createTransport() {
},
sendMail() {
}
}
//nodemailer-mailgun-transport.js
module.exports = {
mailGun() {
}
}
And here are my tests
const request = require('supertest')
const jwt = require('jsonwebtoken')
const mongoose = require('mongoose')
const app = require('../src/app')
const User = require('../src/models/user')
const userOneId = mongoose.Types.ObjectId()
const userOne = {
_id: userOneId,
name: 'Jon',
email: 'jon#example.com',
password: 'JonTest123',
tokens: [{
token: jwt.sign({ _id: userOneId }, process.env.JWT_SECRET)
}]
}
beforeEach(async () => {
await User.deleteMany()
await new User(userOne).save()
})
test('Should signup a new user', async() => {
const response = await request(app).post('/users').send({
name: 'Caleb',
email: 'caleb#example.com',
password: 'TestPass637!'
}).expect(201)
//Assert that the database was changed correctly
const user = await User.findById(response.body.user._id)
expect(user).not.toBeNull()
//Assertions about the response
expect(response.body).toMatchObject({
user: {
name: 'Caleb',
email: 'caleb#example.com'
},
token: user.tokens[0].token
})
expect(user.password).not.toBe('TestPass637!')
})
And I have Jest setup to look for the __mocks__ file in the tests directory, which is where I have it
But when I run my tests, I get
TypeError: mailGun is not a function
Why doesn't it recognize the mailGun() function?
The nodemailer-mailgun-transport should return a function so that you can pass the auth to it. In your test code mailGun refers to the default output, not a property.
//nodemailer-mailgun-transport.js
module.exports = (auth) => {
// do something with auth, if you want
}
var id = req.query.id;
var username = req.query.name;
var password = req.query.password;
console.log(req.query);
var data = {
people:{
}
}
data.people[id] = {
username: username,
password: password,
degignation : 1
}
let userjson = jsonfile.readFileSync(path.join(__dirname,'database','people'));
console.log(userjson);
userjson.people[id] = {
username: username,
password : password,
degignation: 1
}
jsonfile.writeFileSync(path.join(__dirname,'database','people'),userjson,{spaces:2});`
i want to write js object in json file. but it show the error TypeError: Cannot set property '18dit075' of undefined in node js. note my people.json file is empty. i need a help in express js. please help me
You need to use JSON.stringify while writing to JSON. You also need to use .json as an extension.
Better yet you can use https://www.npmjs.com/package/write-json-file & https://www.npmjs.com/package/load-json-file to avoid minor errors :)
Here's how I'd do it:
const loadJsonFile = require('load-json-file');
const writeJsonFile = require('write-json-file');
const id = req.query.id
const username = req.query.name
const password = req.query.password
console.log(req.query)
(async () => {
const data = {
people: {},
}
data.people[id] = {
username: username,
password: password,
degignation: 1,
}
const filePath = path.join(__dirname, 'database/people.json')
let userjson = await loadJsonFile(filePath);
console.log(userjson)
userjson.people[id] = {
name: username,
password: password,
degignation: 1,
}
await writeJsonFile(filePath, userjson, {indent: 2});
})();
I'm creating API tests with async-await using Supertest and Mocha.
In the accountsData.js file I created a function to generate random test accounts.
In the accountsHelper.js file I created a function to create unlimited accounts using a while loop
When I run tests on the post_accounts.js file, the first account is created successfully, but from the second account, the data generated in the accountsData.js file is already repeated.
Why isn't data randomly generated when I create more than one account using data from the accountsData.js file?
accountsData.js
const casual = require('casual');
function randomAccount() {
return {
'email': casual.email,
'password': '123456',
};
}
module.exports = {
randomAccount,
};
accountsHelper.js
const request = require('supertest');
const commonData = require('../data/commonData');
/* eslint-disable no-console */
const accountList = [];
let counterAccounts;
module.exports = {
async createAccount(account, accountsToCreate = 2, validateResponse = true) {
counterAccounts = 0;
while (counterAccounts < accountsToCreate) {
try {
const res = await request(commonData.environment.staging)
.post(commonData.endpoint.accounts)
.send(account);
if (validateResponse === true) {
if (res.status === commonData.statusCode.ok) {
accountList.push(res.body);
} else {
throw new Error('Email already exists\n\n' + JSON.stringify(res.body, null, ' '));
}
} else {
return res.body;
}
} catch (err) {
console.log(err);
}
counterAccounts++;
}
return accountList;
},
};
post_accounts.js
const accountsData = require('../../data/accountsData');
const accountsHelper = require('../../helpers/accountsHelper');
const account = accountsData.randomAccount();
describe('Create accounts with email and password', () => {
context('valid accounts', () => {
it('should create an account successfully', async() => {
const res = await accountsHelper.createAccount(account);
// eslint-disable-next-line no-console
console.log(res);
});
});
});
API response:
Create accounts with email and password
valid accounts
Error: Email already exists
{
"error": {
"statusCode": 422,
"name": "ValidationError",
"message": "The `account` instance is not valid. Details: `email` Email already exists (value: \"Lemuel.Lynch#Susan.net\").",
"details": {
"context": "account",
"codes": {
"email": [
"uniqueness"
]
},
"messages": {
"email": [
"Email already exists"
]
}
}
}
}
at Object.createAccount (/Users/rafael/Desktop/projects/services/test/helpers/accountsHelper.js:24:19)
at process._tickCallback (internal/process/next_tick.js:68:7)
[ { 'privacy-terms': false,
'created-date': '2019-08-24T10:00:34.094Z',
admin: false,
isQueued: false,
lastReleaseAttempt: '1970-01-01T00:00:00.000Z',
'agreed-to-rules': { agreed: false },
email: 'Lemuel.Lynch#Susan.net',
id: '5d610ac213c07d752ae53d91' } ]
✓ should create an account successfully (2243ms)
1 passing (2s)
The code that you posted doesn't correspond to the code that you're describing in prose.
However, I tested your accountsData.js file, in the way that your words (but not your code) say that you're using it, and it works fine.
// main.js
const { createPerson } = require(__dirname + '/accountsData')
console.log(createPerson())
console.log(createPerson())
console.log(createPerson())
console.log(createPerson())
console.log(createPerson())
Output from running it once:
$ node main.js
{ email: 'Anne_Ebert#Macie.com', password: '123456' }
{ email: 'Manley.Lindgren#Kshlerin.info', password: '123456' }
{ email: 'McClure_Thurman#Zboncak.net', password: '123456' }
{ email: 'Breitenberg.Alexander#Savannah.com', password: '123456' }
{ email: 'Keely.Mann#Stark.io', password: '123456' }
And again:
$ node main.js
{ email: 'Destany_Herman#Penelope.net', password: '123456' }
{ email: 'Narciso_Roob#gmail.com', password: '123456' }
{ email: 'Burnice_Rice#yahoo.com', password: '123456' }
{ email: 'Roma_Nolan#yahoo.com', password: '123456' }
{ email: 'Lilla_Beier#yahoo.com', password: '123456' }
Nothing in the code that you posted is actually requiring or using accountsData.js. If you change your code to use it, I think you'll see, like I do, that it works.
Problem is, you are generating the random account and storing it in a variable 'post_accounts.js(line 3)'. So, when you create an account, you are using the same payload to create multiple accounts, which obviously throws an error.
I just modified the accountHelper to properly handle your scenario. Hope this helps.
Note: The code is not tested, I just wrote it from my mind. Please test and let me know if it works.
// accountsHelper.js
const request = require('supertest');
const commonData = require('../data/commonData');
const accountsData = require('../../data/accountsData');
/* eslint-disable no-console */
const accountList = [];
module.exports = {
async createAccount(account, accountsToCreate = 1, validateResponse = true) {
// creates an array of length passed in accountsToCreate param
return (await Promise.all(Array(accountsToCreate)
.fill()
.map(async () => {
try {
const res = await request(commonData.environment.staging)
.post(commonData.endpoint.accounts)
// takes account if passed or generates a random account
.send(account || accountsData.randomAccount());
// validates and throw error if validateResponse is true
if (validateResponse === true && (res.status !== commonData.statusCode.ok)) {
throw new Error(
'Email already exists\n\n' +
JSON.stringify(res.body, null, ' ')
);
}
// return response body by default
return res.body;
} catch (e) {
console.error(e);
// return null if the create account service errors out, just to make sure the all other create account call doesnt fail
return null;
}
})))
// filter out the null(error) responses
.filter(acc => acc);
}
};
//post_accounts.js
const accountsHelper = require('../../helpers/accountsHelper');
const accountsData = require('../../data/accountsData');
const GENERATE_RANDOM_ACCOUNT = null;
describe('Create accounts with email and password', () => {
context('valid accounts', () => {
it('should create an account successfully', async () => {
const result = await accountsHelper.createAccount();
expect(result.length).toEquals(1);
});
it('should create 2 accounts successfully', async () => {
const result = await accountsHelper.createAccount(GENERATE_RANDOM_ACCOUNT, 2);
expect(result.length).toEquals(2);
});
it('should not create duplicate accounts', async () => {
const account = accountsData.randomAccount();
// here we are trying to create same account twice
const result = await accountsHelper.createAccount(account, 2);
// expected result should be one as the second attempt will fail with duplicate account
expect(result.length).toEquals(1);
});
});
});