Merge pull request #499 from lbryio/tor-middleware

Tor middleware
This commit is contained in:
Bill Bittner 2018-06-28 17:59:55 -07:00 committed by GitHub
commit 76acc9e661
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 192 additions and 30 deletions

View file

@ -35,6 +35,10 @@ const speechPassport = require('./server/speechPassport');
const {
details: { port: PORT },
auth: { sessionKey },
startup: {
performChecks,
performUpdates,
},
} = require('@config/siteConfig');
function Server () {
@ -97,31 +101,70 @@ function Server () {
/* create server */
this.server = http.Server(this.app);
};
this.startServerListening = () => {
logger.info(`Starting server on ${PORT}...`);
return new Promise((resolve, reject) => {
this.server.listen(PORT, () => {
logger.info(`Server is listening on PORT ${PORT}`);
resolve();
})
});
};
this.syncDatabase = () => {
logger.info(`Syncing database...`);
return createDatabaseIfNotExists()
.then(() => {
db.sequelize.sync();
})
};
this.performChecks = () => {
if (!performChecks) {
return;
}
logger.info(`Performing checks...`);
return Promise.all([
getWalletBalance(),
])
.then(([walletBalance]) => {
logger.info('Starting LBC balance:', walletBalance);
})
};
this.performUpdates = () => {
if (!performUpdates) {
return;
}
logger.info(`Peforming updates...`);
return Promise.all([
[],
db.Tor.refreshTable(),
])
.then(([updatedBlockedList, updatedTorList]) => {
logger.info('Blocked list updated, length:', updatedBlockedList.length);
logger.info('Tor list updated, length:', updatedTorList.length);
})
};
this.start = () => {
this.initialize();
this.createApp();
this.createServer();
/* start the server */
logger.info('getting LBC balance & syncing database...');
Promise.all([
this.syncDatabase(),
getWalletBalance(),
])
.then(([syncResult, walletBalance]) => {
logger.info('starting LBC balance:', walletBalance);
return this.server.listen(PORT, () => {
logger.info(`Server is listening on PORT ${PORT}`);
})
this.syncDatabase()
.then(() => {
return this.startServerListening();
})
.then(() => {
return Promise.all([
this.performChecks(),
this.performUpdates(),
])
})
.then(() => {
logger.info('Spee.ch startup is complete');
})
.catch(error => {
if (error.code === 'ECONNREFUSED') {
return logger.error('Connection refused. The daemon may not be running.')
} else if (error.code === 'EADDRINUSE') {
return logger.error('Server could not start listening. The port is already in use.');
} else if (error.message) {
logger.error(error.message);
}

View file

@ -21,9 +21,9 @@ const authenticateUser = require('./authentication.js');
*/
const claimPublish = ({ body, files, headers, ip, originalUrl, user }, res) => {
const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res) => {
// logging
logger.info('PUBLISH REQUEST:', {
logger.info('Publish request:', {
ip,
headers,
body,

View file

@ -0,0 +1,25 @@
const logger = require('winston');
const db = require('../../../models');
/*
Route to update and return tor exit nodes that can connect to this ip address
*/
const getTorList = (req, res) => {
db.Tor.refreshTable()
.then( result => {
logger.debug('number of records', result.length);
res.status(200).json(result);
})
.catch((error) => {
logger.error(error);
res.status(500).json({
success: false,
error,
})
});
};
module.exports = getTorList;

View file

@ -0,0 +1,32 @@
const logger = require('winston');
const db = require('../models');
const torCheck = (req, res, next) => {
const { ip } = req;
logger.debug(`tor check for: ${ip}`);
return db.Tor.findAll(
{
where: {
address: ip,
},
raw: true,
})
.then(result => {
logger.debug('tor check results:', result);
if (result.length >= 1) {
logger.info('Tor request blocked:', ip);
const failureResponse = {
success: false,
message: 'Unfortunately this api route is not currently available for tor users. We are working on a solution that will allow tor users to use this endpoint in the future.',
};
res.status(403).json(failureResponse);
} else {
next();
}
})
.catch(error => {
logger.error(error);
});
};
module.exports = torCheck;

View file

@ -8,6 +8,7 @@ const File = require('./file.js');
const Request = require('./request.js');
const User = require('./user.js');
const Blocked = require('./blocked.js');
const Tor = require('./tor.js');
const {database, username, password} = require('@config/mysqlConfig');
if (!database || !username || !password) {
@ -50,6 +51,7 @@ db['File'] = sequelize.import('File', File);
db['Request'] = sequelize.import('Request', Request);
db['User'] = sequelize.import('User', User);
db['Blocked'] = sequelize.import('Blocked', Blocked);
db['Tor'] = sequelize.import('Tor', Tor);
// run model.association for each model in the db object that has an association
logger.info('associating db models...');

56
server/models/tor.js Normal file
View file

@ -0,0 +1,56 @@
const { details: { ipAddress } } = require('@config/siteConfig');
module.exports = (sequelize, { STRING }) => {
const Tor = sequelize.define(
'Tor',
{
address: {
type : STRING,
allowNull: false,
},
fingerprint: {
type : STRING,
allowNull: true,
},
},
{
freezeTableName: true,
}
);
Tor.refreshTable = function () {
let torList = [];
return fetch(`https://check.torproject.org/api/bulk?ip=${ipAddress}&port=80`)
.then(response => {
return response.json();
})
.then(jsonResponse => {
for (let i = 0; i < jsonResponse.length; i++) {
torList.push({
address : jsonResponse[i].Address,
fingerprint: jsonResponse[i].Fingerprint,
});
}
// clear the table
return this.destroy({
truncate: true,
});
})
.then(() => {
// fill the table
return this.bulkCreate(torList);
})
.then(() => {
// return the new table
return this.findAll({
attributes: ['address', 'fingerprint'],
raw : true,
});
})
.catch(error => {
throw error;
});
};
return Tor;
};

View file

@ -14,29 +14,33 @@ const claimShortId = require('../../controllers/api/claim/shortId');
const fileAvailability = require('../../controllers/api/file/availability');
const userPassword = require('../../controllers/api/user/password');
const publishingConfig = require('../../controllers/api/config/site/publishing');
const getTorList = require('../../controllers/api/tor');
const multipartMiddleware = require('../utils/multipartMiddleware');
const multipartMiddleware = require('../../middleware/multipartMiddleware');
const torCheckMiddleware = require('../../middleware/torCheckMiddleware');
module.exports = (app) => {
// channel routes
app.get('/api/channel/availability/:name', channelAvailability);
app.get('/api/channel/short-id/:longId/:name', channelShortId);
app.get('/api/channel/data/:channelName/:channelClaimId', channelData);
app.get('/api/channel/claims/:channelName/:channelClaimId/:page', channelClaims);
app.get('/api/channel/availability/:name', torCheckMiddleware, channelAvailability);
app.get('/api/channel/short-id/:longId/:name', torCheckMiddleware, channelShortId);
app.get('/api/channel/data/:channelName/:channelClaimId', torCheckMiddleware, channelData);
app.get('/api/channel/claims/:channelName/:channelClaimId/:page', torCheckMiddleware, channelClaims);
// claim routes
app.get('/api/claim/availability/:name', claimAvailability);
app.get('/api/claim/blocked-list/', claimBlockedList);
app.get('/api/claim/data/:claimName/:claimId', claimData);
app.get('/api/claim/get/:name/:claimId', claimGet);
app.get('/api/claim/list/:name', claimList);
app.post('/api/claim/long-id', claimLongId); // should be a get
app.post('/api/claim/publish', multipartMiddleware, claimPublish);
app.get('/api/claim/resolve/:name/:claimId', claimResolve);
app.get('/api/claim/short-id/:longId/:name', claimShortId);
app.get('/api/claim/availability/:name', torCheckMiddleware, claimAvailability);
app.get('/api/claim/blocked-list/', torCheckMiddleware, claimBlockedList);
app.get('/api/claim/data/:claimName/:claimId', torCheckMiddleware, claimData);
app.get('/api/claim/get/:name/:claimId', torCheckMiddleware, claimGet);
app.get('/api/claim/list/:name', torCheckMiddleware, claimList);
app.post('/api/claim/long-id', torCheckMiddleware, claimLongId); // note: should be a 'get'
app.post('/api/claim/publish', torCheckMiddleware, multipartMiddleware, claimPublish);
app.get('/api/claim/resolve/:name/:claimId', torCheckMiddleware, claimResolve);
app.get('/api/claim/short-id/:longId/:name', torCheckMiddleware, claimShortId);
// file routes
app.get('/api/file/availability/:name/:claimId', fileAvailability);
app.get('/api/file/availability/:name/:claimId', torCheckMiddleware, fileAvailability);
// user routes
app.put('/api/user/password/', userPassword);
app.put('/api/user/password/', torCheckMiddleware, userPassword);
// configs
app.get('/api/config/site/publishing', publishingConfig);
app.get('/api/config/site/publishing', torCheckMiddleware, publishingConfig);
// tor
app.get('/api/tor', torCheckMiddleware, getTorList);
};