OTP generation in nodejs using speakeasy :set expiry time - javascript

I am using https://www.npmjs.com/package/speakeasy to generate OTP and i would like the expiry to 10 minutes.
Here is the code for generation
const generateOtp = function generateOtp() {
let token = speakeasy.totp({
secret:process.env.OTP_KEY,
encoding: 'base32',
digits:4,
window:10
});
return token;
}
Verify OTP
const verifyOtp = function verifyOtp(token){
let expiry = speakeasy.totp.verify({
secret:process.env.OTP_KEY,
encoding: 'base32',
token: token,
window:10
});
console.log(expiry)
}
But I don't know how to set the expiry to 10 minutes??

Reading the documentation you can find out that the base step is 30 seconds, so if you want to have an expiration time of 10 minutes you need to set up the step to 60. Then, using the verifyDelta method you should be able to check if the token expired.
const generateOtp = function generateOtp() {
let token = speakeasy.totp({
secret:process.env.OTP_KEY,
encoding: 'base32',
digits:4,
step: 60,
window:10
});
return token;
}
const verifyOtp = function verifyOtp(token){
let expiry = speakeasy.totp.verifyDelta({
secret:process.env.OTP_KEY,
encoding: 'base32',
token: token,
step: 60,
window:10
});
console.log(expiry)
}

Related

set js-cookie value to firebase token

Is it ok to set the value of a cookie to a token? I'm using js-cookie, Firebase auth/firestore and Next.js and I have my cookie set like this inside of my handleUser function:
const handleUser = async (rawUser) => {
if (rawUser) {
const user = await formatUser(rawUser)
const { token, ...userWithoutToken } = user
createUser(user.uid, userWithoutToken)
setUser(user)
cookie.set('colorizer-auth', token, {
expires: 1
})
setLoading(false)
return user
} else {
setUser(false)
cookie.remove('colorizer-auth')
setLoading(false)
return false
}
}
and the token is decoded and set here:
const formatUser = async (user) => {
const decodedToken = await user.getIdTokenResult(true);
const { token, expirationTime } = decodedToken;
return {
uid: user.uid,
email: user.email,
name: user.displayName,
provider: user.providerData[0].providerId,
photoUrl: user.photoURL,
token,
expirationTime,
}
}
I've seen some projects that use the Firebase Auth ID Token (access_token) itself in the cookies but that token is valid only for 1 hour. You'll have to securely store the refresh_token as well so you can refresh the cookie once it expires.
However, I would recommend using session cookies instead for such SSR application. You can set the expiration time ranging 5 minutes to 2 weeks. It might be best to reauthenticate user after this expires.

How would I make the limit based if a user is logged in or not?

I am trying to use express and express-rate-limit to limit anonymous users download limit, the catch is that if the user object sent with the request is true, I want to disable the limit. How would I go about doing it? This is a code snippet:
const limiter = rateLimit({
windowMs: 24 * 60 * 60 * 1000, // 24 hours
max: if (user) { return 0 } else { return 10 }, //THIS IS THE LINE I NEED HELP WITH
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
})
app.use('/link', limiter)
app.post("/link", async (req, res) => {
const premiumLink = req.body.downloadLink;
const password = req.body.password;
const user = req.body.user;
//do function here
According to the express-rate-limit documentation, max can be either a number or a function.
max: number | function
The maximum number of connections to allow during the window before
rate limiting the client.
Can be the limit itself as a number or a (sync/async) function that
accepts the Express request and response objects and then returns a
number.
Here is an example also provided in the documentation:
const isPremium = async (user) => {
// ...
}
const limiter = rateLimit({
// ...
max: async (request, response) => {
if (await isPremium(request.user)) return 10
else return 5
},
})
EDIT:
To better answer, your question, here is how you can achieve what you want to do:
const limiter = rateLimit({
// ...
max: async (request, response) => {
if (request.body.user) return 0
else return 10
},
})

Send a notification every 15 minutes during the day

I want to send a notification within 1 hour of the data I added to Firebase and I want to cancel the notification 1 day after adding the data. Because I don't know JavaScript, and I'm new to the software world yet, I couldn't quite figure out its algorithm, and I wrote something like that. The addedNewCard method works, but I couldn't adjust the time.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().functions);
var newData;
exports.addedNewCard =
functions.firestore.document('Users/{userID}/Cards/{cardID}').onCreate(async
(snapshot, context) => {
const cardID = context.params.cardID;
if (snapshot.empty) {
console.log('No Devices');
return;
}
newData = snapshot.data();
const cardAddedDate = newData.cardAddedDate;
const deviceIdTokens = await admin
.firestore()
.collection('DeviceToken')
.get();
var tokens = [];
for (var token of deviceIdTokens.docs) {
tokens.push(token.data().deviceToken);
}
var payload = {
notification: {
title: 'Tekrar vakti',
body: 'Tekrar etmen gereken kelimeler var!!!',
sound: 'default',
},
data: {
click_action: 'FLUTTER_NOTIFICATIoN_CLICK',
sendCardID: cardID,
}
};
const options = {
priority: "high",
};
try {
await admin.messaging().sendToDevice(tokens, payload, options);
console.log('Notification sent successfully');
} catch (err) {
console.log(err);
}
})
exports.timeSettings = functions.pubsub.schedule('every 1 mins').onRun(async
(context) => {
console.log(context.timestamp);
let now = new Date();
const finishWorking = now.setDate(now.getDate + 1);
const finishWorkingStamp = admin.firestore.Timestamp.fromDate(finishWorking);
db.collection('Users/{userID}/Cards').where('cardAddedDate', '<',
finishWorkingStamp).get().then((snap) => {
if (snap.exist) {
snap.forEach(() => {
return addedNewCard();
}).catch((e) => {
return console.log(e);
});
}
});
})
Thanks to your comment, I would recommend you to use Cloud Task. With Cloud Task you can delay an execution in the futur.
When a user send a data, you can plan the 24H notification in advance (with 1 notification every 15 minutes, for 1 day -> create 96 tasks, the next one with 15 minutes more in the delay than the previous one).
You have code sample here. Have a look on this part, to change the delay
if (inSeconds) {
// The time when the task is scheduled to be attempted.
task.scheduleTime = {
seconds: inSeconds + Date.now() / 1000,
};
}
I wouldn't do the schedule notification in client side, instead, config and send schedule by server side. Try to create thread for client for processing the notifications.
You have to create a firebase cloud function where you need to upgrade your firebase account subscription and use pub-sub.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.scheduledFunctionCrontab = functions.pubsub.schedule('*/15 * * * *').timeZone('Asia/Kolkata').onRun(async (context) => {
console.log('This will be run every 15 minutes');
return null});

Timezone issue in javascript Date object

I am working on an employee time tracking application with its backend on node.js. The problem is when the site is hosted locally it registers the time in gmt +05:30 which is correct as i live in india but when i hosted the site on heroku server (which i think the heroku's server time zone is set to 00:00) and accesses it from same computer. then, it registers the time in gmt +00:00.
Now what i want is that when its hosted on heroku server it should know the time zone of the user (Example if user resides in Los Angeles and creates an entry. then, it should register the entry in GMT-7 timezone)
Screenshot
Code
const postSchema = {
username: String,
entry: String,
rawEntry: Number,
exit: String,
rawExit: Number,
duration: String,
complete: Boolean,
createdAt: {
type: Date,
default: Date.now()
}
};
logEntry Route
app.get('/logEntry', function(req, res) {
if (req.isAuthenticated()) {
const t = new Date();
const now = date.format(t, 'DD/MMM/YYYY ddd hh:mm:ss A Z');
const rawNow = Date.now();
const post = new Post({
username: nameUser,
entry: now,
rawEntry: rawNow,
complete: false
});
post.save(function(err) {
if (err) {
console.log(err);
}
res.redirect('/logged');
});
} else {
res.redirect('/');
}
});
This is a very common problem that we face with timezone.
Client side get getTimezoneOffset and add or remove seconds that are over.
const d = new Date();
const n = d.getTimezoneOffset();
console.log("your PC or laptop timezone more or less in seconds", n); // -330
So, when you will run this code in local that time as you told you are having gmt +05:30 getTimezoneOffset will output -330 sec means 5 hour and 30 mins.
So you can remove these seconds from the current time and set accordingly.
or
You can use in build javascript function
const d1 = new Date();
console.log(d1); //Thu Aug 29 2019 17:56:14 GMT+0530
d1.toUTCString(); // Thu, 29 Aug 2019 12:26:39 GMT
Check the differance is +5:30 hours.
I solved this problem by executing new Date() on the client side and then passing in url to the server for further action.
Client side code =>
<button onclick="createLogin()" class="btn btn-outline-primary btn-lg btn-block entryBtn">
CREATE LOGIN ENTRY
</button>
<script>
function createLogin() {
let t = new Date();
console.log(t);
let url = '/logEntry/' + t;
window.location = url;
}
</script>
Server side code =>
app.get('/logEntry/:date', function(req, res) {
if (req.isAuthenticated()) {
const now = req.params.date;
const nowDayTime = now.substring(0, 25);
const timeZone = now.substring(25, now.length);
const rawNow = Date.now();
const post = new Post({
username: nameUser,
entryDayTime: nowDayTime,
entryTimeZone: timeZone,
rawEntry: rawNow,
complete: false
});
post.save(function(err) {
if (err) {
console.log(err);
}
res.redirect('/logged');
});
} else {
res.redirect('/');
}
});

Truffle test gives "Error: Attempting to run transaction which calls a contract function, but recipient address ___ is not a contract address"

When I run truffle test on terminal I get the following error Error: Attempting to run transaction which calls a contract function, but recipient address 0x3ad2c00512808bd7fafa6dce844a583621f3df87 is not a contract address I don't understand why I get this because my build folder is normal meaning if I run truffle migrate --reset the address in the terminal is the same as the address in the build file. when I run truffle migrate it works. Also, every time I run the truffle test the recipient address always changes. I don't know what do to please help.
One other thing this only happens once I use the code selfdestruct(admin); then I get this error. the admin is = to msg.sender which is the first account in the ganache so I don't know what's wrong.
I am using this video. I have done all the other videos of this guy and everything is fine until now at minute 15:11 he does the final test and for him, it works but for me, it gives me the error above.
Anyone, please help
These is my test (javascript)
var CinoCoin = artifacts.require("./CinoCoin.sol");
var CinoCoinSale = artifacts.require("./CinoCoinSale.sol");
contract('CinoCoinSale', function(accounts) {
var tokenInstance;
var tokenSaleInstance;
var admin = accounts[0];
var buyer = accounts[1];
var tokenPrice = 1000000000000000; // in wei 0.01 ether
var tokensAvailable = 750000;
var numberOfTokens;
it('initializes the contract with the correct values', function() {
return CinoCoinSale.deployed().then(function(instance) {
tokenSaleInstance = instance;
return tokenSaleInstance.address
}).then(function(address) {
assert.notEqual(address, 0x0, 'has contract address');
return tokenSaleInstance.tokenContract();
}).then(function(address) {
assert.notEqual(address, 0x0, 'has token contract address');
return tokenSaleInstance.tokenPrice();
}).then(function(price) {
assert.equal(price, tokenPrice, 'token price is correct');
});
});
it('facilitats token buying', function() {
return CinoCoin.deployed().then(function(instance) {
//Grab token instance first
tokenInstance = instance;
return CinoCoinSale.deployed();
}).then(function(instance) {
//Then grab token sale instance
tokenSaleInstance = instance;
//Provision 75% of all tokens to the token sale contract
return tokenInstance.transfer(tokenSaleInstance.address, tokensAvailable, { from: admin})
}).then(function(receipt) {
numberOfTokens = 10;
return tokenSaleInstance.buyTokens(numberOfTokens, { from: buyer, value: numberOfTokens * tokenPrice })
}).then(function(receipt) {
assert.equal(receipt.logs.length, 1, 'triggers one event');
assert.equal(receipt.logs[0].event, 'Sell', 'should be the "Sell" event');
assert.equal(receipt.logs[0].args._buyer, buyer, 'logs the account that purchased the tokens');
assert.equal(receipt.logs[0].args._amount, numberOfTokens, 'logs the number of tokens purchased');
return tokenSaleInstance.tokensSold();
}).then(function(amount) {
assert.equal(amount.toNumber(), numberOfTokens, 'increments the number of tokens sold');
return tokenInstance.balanceOf(buyer);
}).then(function(balance) {
assert.equal(balance.toNumber(), numberOfTokens);
return tokenInstance.balanceOf(tokenSaleInstance.address);
}).then(function(balance) {
assert.equal(balance.toNumber(), tokensAvailable - numberOfTokens);
//Try to buy tokens different from the ether value
return tokenSaleInstance.buyTokens(numberOfTokens, { from: buyer, value: 1 });
}).then(assert.fail).catch(function(error) {
assert(error.message.indexOf('revert') >= 0, 'msg.value must equal number of tokens in wei');
return tokenSaleInstance.buyTokens(800000, { from: buyer, value: numberOfTokens * tokenPrice });
}).then(assert.fail).catch(function(error) {
assert(error.message.indexOf('revert') >= 0, 'connot purchase more tokens than available');
});
});
it('ends token sale', function () {
return CinoCoin.deployed().then(function(instance) {
//Grab token instance first
tokenInstance = instance;
return CinoCoinSale.deployed();
}).then(function(instance) {
//Then grab token sale instance
tokenSaleInstance = instance;
//try to end sale from account other than admin
return tokenSaleInstance.endSale({ from: buyer });
}).then(assert.fail).catch(function(error) {
assert(error.message.indexOf('revert' >= 0, 'must be admin to end sale'));
//End sale as admin
return tokenSaleInstance.endSale({ from: admin });
}).then(function(receipt) {
return tokenInstance.balanceOf(admin);
}).then(function(balance) {
assert.equal(balance.toNumber(), 999990, 'returns all unsold cino coins to admin');
//Check that the token price was reset when selfFestruct was called
return tokenSaleInstance.tokenPrice();
}).then(function(price) {
assert.equal(price.toNumber(), 0, 'token price was reset');
});
});
});
And this is my contract code (solidity)
pragma solidity ^0.4.23;
import "./CinoCoin.sol";
contract CinoCoinSale {
address admin;
CinoCoin public tokenContract;
uint256 public tokenPrice;
uint256 public tokensSold;
event Sell(address _buyer, uint256 _amount);
function CinoCoinSale(CinoCoin _tokenContract, uint256 _tokenPrice) public {
//Assign an admin / an external account connected to the blockchain that has certain priviliges
admin = msg.sender;
//Assign token contract
tokenContract = _tokenContract;
//Token Price how much the token will cost
tokenPrice = _tokenPrice;
}
//multiply function for
function multiply(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x);
}
//Buy tokens
function buyTokens(uint256 _numberOfTokens) public payable {
//Require that the value is equal to tokens
require(msg.value == multiply(_numberOfTokens, tokenPrice));
//Require that there are enough tokens in the contrat
require(tokenContract.balanceOf(this) >= _numberOfTokens);
//Require the transfer is successful
require(tokenContract.transfer(msg.sender, _numberOfTokens));
//Keep track of number of tokens sold
tokensSold += _numberOfTokens;
//Trigger a sell event
Sell(msg.sender, _numberOfTokens);
}
//ending token CinoCoinSale
function endSale()public {
//Only an admin can end the end the sale
require(msg.sender == admin);
//Transfer the amount of token in the sale back to the admin
require(tokenContract.transfer(admin, tokenContract.balanceOf(this)));
//Destroy contract
selfdestruct(admin);
}
}
It says my test are passing when I comment out the selfdestruct(admin); so it seems to be a probelm with that
thanks for the help
glad you fixed the error already. While looking at your code I noticed that the test file is quite difficult to follow because of the large promise chains. I converted the file to async/await, which might be easier to maintain and debug in the future.
I also noticed that you are trying to assert emitted events and reverts by manually checking the logs, and catching the revert exception. I actually wrote a library to make this a bit easier, so I added the code for this as well.
The library can be installed with npm:
npm install truffle-assertions
After this, the new test code should work. I hope this helps, and good luck with your Dapp development.
const CinoCoin = artifacts.require("CinoCoin");
const CinoCoinSale = artifacts.require("CinoCoinSale");
const truffleAssert = require("truffle-assertions");
contract('CinoCoinSale', function(accounts) {
let tokenInstance;
let tokenSaleInstance;
let admin = accounts[0];
let buyer = accounts[1];
let tokenPrice = 1000000000000000; // in wei 0.01 ether
let tokensAvailable = 750000;
it('initializes the contract with the correct values', async function() {
tokenInstance = await CinoCoin.deployed();
tokenSaleInstance = await CinoCoinSale.deployed();
assert.notEqual(tokenSaleInstance.address, 0x0, 'has contract address');
assert.notEqual(await tokenSaleInstance.tokenContract(), 0x0, 'has token contract address');
assert.equal(await tokenSaleInstance.tokenPrice(), tokenPrice, 'token price is correct');
assert.equal(await tokenSaleInstance.admin(), admin, 'admin is correct');
});
it('facilitates token buying', async function() {
tokenInstance = await CinoCoin.deployed();
tokenSaleInstance = await CinoCoinSale.deployed();
await tokenInstance.transfer(tokenSaleInstance.address, tokensAvailable, { from: admin });
const numberOfTokens = 10;
const receipt = await tokenSaleInstance.buyTokens(numberOfTokens, { from: buyer, value: numberOfTokens * tokenPrice });
truffleAssert.eventEmitted(receipt, 'Sell', (ev) => {
return ev._buyer === buyer && ev._amount.toNumber() === numberOfTokens;
});
const tokensSold = await tokenSaleInstance.tokensSold();
assert.equal(tokensSold.toNumber(), numberOfTokens, 'increments the number of tokens sold');
const buyerBalance = await tokenInstance.balanceOf(tokenSaleInstance.address);
assert.equal(buyerBalance.toNumber(), numberOfTokens);
const tokenSaleBalance = await tokenInstance.balanceOf(tokenSaleInstance.address);
assert.equal(tokenSaleBalance.toNumber(), tokensAvailable - numberOfTokens);
truffleAssert.reverts(
tokenSaleInstance.buyTokens(numberOfTokens, { from: buyer, value: 1 }),
null,
'msg.value must equal number of tokens in wei'
);
truffleAssert.reverts(
tokenSaleInstance.buyTokens(800000, { from: buyer, value: numberOfTokens * tokenPrice }),
null,
'connot purchase more tokens than available'
);
});
it('ends token sale', async function () {
tokenInstance = await CinoCoin.deployed();
tokenSaleInstance = await CinoCoinSale.deployed();
truffleAssert.reverts(tokenSaleInstance.endSale({ from: buyer }), null, 'must be admin to end sale');
await tokenSaleInstance.endSale({ from: admin });
const adminBalance = await tokenInstance.balanceOf(admin);
assert.equal(adminBalance.toNumber(), 999990, 'returns all unsold cino coins to admin');
const tokenPrice = await tokenSaleInstance.tokenPrice();
assert.equal(tokenPrice.toNumber(), 0, 'token price was reset');
});
});

Categories

Resources