Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/tokens #335

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 70 additions & 28 deletions class/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class User {
return this._password;
}
getAccessToken() {
return this._acess_token;
return this._access_token;
}
getRefreshToken() {
return this._refresh_token;
Expand All @@ -48,37 +48,41 @@ export class User {
let access_token = authorization.replace('Bearer ', '');
let userid = await this._redis.get('userid_for_' + access_token);

if (userid) {
this._userid = userid;
return true;
if (!userid) {
return false
}

return false;
let refresh_token = await this._redis.get('refresh_token_for_' + userid)
if (refresh_token === access_token) {
return false
}

this._userid = userid;
return true;
}

async loadByRefreshToken(refresh_token) {
let userid = await this._redis.get('userid_for_' + refresh_token);
if (userid) {
this._userid = userid;
await this._generateTokens();
return true;

if (!userid) {
return false;
}

return false;
let access_token = await this._redis.get('access_token_for_' + userid)
if (access_token === refresh_token) {
return false
}

this._userid = userid;
await this._generateTokens();
return true;
}

async create() {
let buffer = crypto.randomBytes(10);
let login = buffer.toString('hex');

buffer = crypto.randomBytes(10);
let password = buffer.toString('hex');
this._login = this._generateDigest();
this._password = this._generateDigest();
this._userid = this._generateDigest();

buffer = crypto.randomBytes(24);
let userid = buffer.toString('hex');
this._login = login;
this._password = password;
this._userid = userid;
await this._saveUserToDatabase();
}

Expand Down Expand Up @@ -479,23 +483,61 @@ export class User {
}

async _generateTokens() {
let buffer = crypto.randomBytes(20);
this._acess_token = buffer.toString('hex');
await this._invalidateCurrentTokens();

await this._generateAccessToken();
await this._generateRefreshToken();
}

async _invalidateCurrentTokens() {
this._access_token = await this._redis.get('access_token_for_' + this._userid);
this._refresh_token = await this._redis.get('refresh_token_for_' + this._userid);

await this._redis.del('access_token_for_' + this._userid);
await this._redis.del('refresh_token_for_' + this._userid);
await this._redis.del('userid_for_' + this._access_token);
await this._redis.del('userid_for_' + this._refresh_token);

this._access_token = null
this._refresh_token = null
}

async _generateAccessToken() {
this._access_token = this._generateDigest();

buffer = crypto.randomBytes(20);
this._refresh_token = buffer.toString('hex');
const key_UId_AT = 'userid_for_' + this._access_token;
const key_AT_UId = 'access_token_for_' + this._userid;

await this._redis.set('userid_for_' + this._acess_token, this._userid);
await this._redis.set('userid_for_' + this._refresh_token, this._userid);
await this._redis.set('access_token_for_' + this._userid, this._acess_token);
await this._redis.set('refresh_token_for_' + this._userid, this._refresh_token);
await this._redis.set(key_UId_AT, this._userid);
await this._redis.set(key_AT_UId, this._access_token);

await this._redis.expire(key_UId_AT, accessTokenLifeTime);
await this._redis.expire(key_AT_UId, accessTokenLifeTime);
}

async _generateRefreshToken() {
this._refresh_token = this._generateDigest();

const key_UId_RT = 'userid_for_' + this._refresh_token;
const key_RT_UId = 'refresh_token_for_' + this._userid;

await this._redis.set(key_UId_RT, this._userid);
await this._redis.set(key_RT_UId, this._refresh_token);

await this._redis.expire(key_UId_RT, refreshTokenLifeTime);
await this._redis.expire(key_RT_UId, refreshTokenLifeTime);
}

async _saveUserToDatabase() {
let key;
await this._redis.set((key = 'user_' + this._login + '_' + this._hash(this._password)), this._userid);
}

_generateDigest() {
const buffer = crypto.randomBytes(256);
return crypto.createHash('sha1').update(buffer).digest('hex');
}

/**
* Fetches all onchain txs for user's address, and compares them to
* already imported txids (stored in database); Ones that are not imported -
Expand Down
4 changes: 4 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ let config = {
rateLimit: 200,
forwardReserveFee: 0.01, // default 0.01
intraHubFee: 0.003, // default 0.003
auth: {
accessTokenLifeTime: 3600,
refreshTokenLifeTime: 86400,
},
bitcoind: {
rpc: 'http://login:[email protected]:8332/wallet/wallet.dat',
},
Expand Down
33 changes: 20 additions & 13 deletions controllers/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ redis.monitor(function (err, monitor) {
/** GLOBALS */
global.forwardFee = config.forwardReserveFee || 0.01;
global.internalFee = config.intraHubFee || 0.003;
global.accessTokenLifeTime = config.auth?.accessTokenLifeTime || 3600;
global.refreshTokenLifeTime = config.auth?.refreshTokenLifeTime || 86400;
/****** END SET FEES FROM CONFIG AT STARTUP ******/

let bitcoinclient = require('../bitcoin');
Expand Down Expand Up @@ -157,23 +159,28 @@ router.post('/create', postLimiter, async function (req, res) {

router.post('/auth', postLimiter, async function (req, res) {
logger.log('/auth', [req.id]);
if (!((req.body.login && req.body.password) || req.body.refresh_token)) return errorBadArguments(res);

let u = new User(redis, bitcoinclient, lightning);
const u = new User(redis, bitcoinclient, lightning);

if (req.body.refresh_token) {
// need to refresh token
if (await u.loadByRefreshToken(req.body.refresh_token)) {
res.send({ refresh_token: u.getRefreshToken(), access_token: u.getAccessToken() });
} else {
return errorBadAuth(res);
}
let authenticated = false
if (req.body.login && req.body.password) {
authenticated = await u.loadByLoginAndPassword(req.body.login, req.body.password);
} else if (req.body.refresh_token) {
authenticated = await u.loadByRefreshToken(req.body.refresh_token)
} else {
// need to authorize user
let result = await u.loadByLoginAndPassword(req.body.login, req.body.password);
if (result) res.send({ refresh_token: u.getRefreshToken(), access_token: u.getAccessToken() });
else errorBadAuth(res);
return errorBadArguments(res);
}

if (!authenticated) {
return errorBadAuth(res);
}

return res.send({
token_type: 'bearer',
refresh_token: u.getRefreshToken(),
access_token: u.getAccessToken(),
expires_in: accessTokenLifeTime,
});
});

router.post('/addinvoice', postLimiter, async function (req, res) {
Expand Down