Merge pull request #428 from lbryio/412-blocked_content
412 blocked content
This commit is contained in:
commit
832e18072b
80 changed files with 1121 additions and 958 deletions
2
index.js
2
index.js
|
@ -55,7 +55,7 @@ function Server () {
|
|||
app.use(requestLogger);
|
||||
|
||||
// configure passport
|
||||
const speechPassport = require('./server/speechPassport/index');
|
||||
const speechPassport = require('./server/speechPassport');
|
||||
// initialize passport
|
||||
const sessionKey = siteConfig.auth.sessionKey;
|
||||
app.use(cookieSession({
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
const logger = require('winston');
|
||||
const db = require('../models');
|
||||
|
||||
module.exports = {
|
||||
authenticateUser (channelName, channelId, channelPassword, user) {
|
||||
// case: no channelName or channel Id are provided (anonymous), regardless of whether user token is provided
|
||||
if (!channelName && !channelId) {
|
||||
return {
|
||||
channelName : null,
|
||||
channelClaimId: null,
|
||||
};
|
||||
}
|
||||
// case: channelName or channel Id are provided with user token
|
||||
if (user) {
|
||||
if (channelName && channelName !== user.channelName) {
|
||||
throw new Error('the provided channel name does not match user credentials');
|
||||
}
|
||||
if (channelId && channelId !== user.channelClaimId) {
|
||||
throw new Error('the provided channel id does not match user credentials');
|
||||
}
|
||||
return {
|
||||
channelName : user.channelName,
|
||||
channelClaimId: user.channelClaimId,
|
||||
};
|
||||
}
|
||||
// case: channelName or channel Id are provided with password instead of user token
|
||||
if (!channelPassword) throw new Error('no channel password provided');
|
||||
return module.exports.authenticateChannelCredentials(channelName, channelId, channelPassword);
|
||||
},
|
||||
authenticateChannelCredentials (channelName, channelId, userPassword) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// hoisted variables
|
||||
let channelData;
|
||||
// build the params for finding the channel
|
||||
let channelFindParams = {};
|
||||
if (channelName) channelFindParams['channelName'] = channelName;
|
||||
if (channelId) channelFindParams['channelClaimId'] = channelId;
|
||||
// find the channel
|
||||
db.Channel
|
||||
.findOne({
|
||||
where: channelFindParams,
|
||||
})
|
||||
.then(channel => {
|
||||
if (!channel) {
|
||||
logger.debug('no channel found');
|
||||
throw new Error('Authentication failed, you do not have access to that channel');
|
||||
}
|
||||
channelData = channel.get();
|
||||
logger.debug('channel data:', channelData);
|
||||
return db.User.findOne({
|
||||
where: { userName: channelData.channelName.substring(1) },
|
||||
});
|
||||
})
|
||||
.then(user => {
|
||||
if (!user) {
|
||||
logger.debug('no user found');
|
||||
throw new Error('Authentication failed, you do not have access to that channel');
|
||||
}
|
||||
return user.comparePassword(userPassword);
|
||||
})
|
||||
.then(isMatch => {
|
||||
if (!isMatch) {
|
||||
logger.debug('incorrect password');
|
||||
throw new Error('Authentication failed, you do not have access to that channel');
|
||||
}
|
||||
logger.debug('...password was a match...');
|
||||
resolve(channelData);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
const db = require('../../../../models');
|
||||
|
||||
const checkChannelAvailability = (name) => {
|
||||
return db.Channel
|
||||
.findAll({
|
||||
where: { channelName: name },
|
||||
})
|
||||
.then(result => {
|
||||
if (result.length >= 1) {
|
||||
throw new Error('That channel has already been claimed');
|
||||
}
|
||||
return name;
|
||||
})
|
||||
.catch(error => {
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = checkChannelAvailability;
|
|
@ -1,6 +1,6 @@
|
|||
const { checkChannelAvailability } = require('../../controllers/publishController.js');
|
||||
const { sendGATimingEvent } = require('../../helpers/googleAnalytics.js');
|
||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
||||
const checkChannelAvailability = require('./checkChannelAvailability.js');
|
||||
const { sendGATimingEvent } = require('../../../../utils/googleAnalytics.js');
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
|
||||
/*
|
||||
|
|
@ -4,7 +4,7 @@ module.exports = {
|
|||
returnPaginatedChannelClaims (channelName, longChannelClaimId, claims, page) {
|
||||
const totalPages = module.exports.determineTotalPages(claims);
|
||||
const paginationPage = module.exports.getPageFromQuery(page);
|
||||
const viewData = {
|
||||
return {
|
||||
channelName : channelName,
|
||||
longChannelClaimId: longChannelClaimId,
|
||||
claims : module.exports.extractPageFromClaims(claims, paginationPage),
|
||||
|
@ -14,7 +14,6 @@ module.exports = {
|
|||
totalPages : totalPages,
|
||||
totalResults : module.exports.determineTotalClaims(claims),
|
||||
};
|
||||
return viewData;
|
||||
},
|
||||
getPageFromQuery (page) {
|
||||
if (page) {
|
||||
|
@ -30,8 +29,7 @@ module.exports = {
|
|||
// logger.debug(`pageNumber ${pageNumber} is number?`, Number.isInteger(pageNumber));
|
||||
const claimStartIndex = (pageNumber - 1) * CLAIMS_PER_PAGE;
|
||||
const claimEndIndex = claimStartIndex + CLAIMS_PER_PAGE;
|
||||
const pageOfClaims = claims.slice(claimStartIndex, claimEndIndex);
|
||||
return pageOfClaims;
|
||||
return claims.slice(claimStartIndex, claimEndIndex);
|
||||
},
|
||||
determineTotalPages (claims) {
|
||||
if (!claims) {
|
29
server/controllers/api/channel/claims/getChannelClaims.js
Normal file
29
server/controllers/api/channel/claims/getChannelClaims.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
const db = require('../../../../models');
|
||||
|
||||
const { returnPaginatedChannelClaims } = require('./channelPagination.js');
|
||||
|
||||
const getChannelClaims = (channelName, channelClaimId, page) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let longChannelClaimId;
|
||||
// 1. get the long channel Id (make sure channel exists)
|
||||
db.Certificate
|
||||
.getLongChannelId(channelName, channelClaimId)
|
||||
.then(result => {
|
||||
longChannelClaimId = result;
|
||||
return db
|
||||
.Claim
|
||||
.getAllChannelClaims(longChannelClaimId);
|
||||
})
|
||||
.then(channelClaimsArray => {
|
||||
// 3. format the data for the view, including pagination
|
||||
let paginatedChannelViewData = returnPaginatedChannelClaims(channelName, longChannelClaimId, channelClaimsArray, page);
|
||||
// 4. return all the channel information and contents
|
||||
resolve(paginatedChannelViewData);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = getChannelClaims;
|
|
@ -1,5 +1,5 @@
|
|||
const { getChannelClaims } = require('../../controllers/serveController.js');
|
||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
const getChannelClaims = require('./getChannelClaims.js');
|
||||
|
||||
const NO_CHANNEL = 'NO_CHANNEL';
|
||||
|
||||
|
@ -16,12 +16,15 @@ const channelClaims = ({ ip, originalUrl, body, params }, res) => {
|
|||
const page = params.page;
|
||||
getChannelClaims(channelName, channelClaimId, page)
|
||||
.then(data => {
|
||||
if (data === NO_CHANNEL) {
|
||||
return res.status(404).json({success: false, message: 'No matching channel was found'});
|
||||
}
|
||||
res.status(200).json({success: true, data});
|
||||
})
|
||||
.catch(error => {
|
||||
if (error === NO_CHANNEL) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'No matching channel was found',
|
||||
});
|
||||
}
|
||||
handleErrorResponse(originalUrl, ip, error, res);
|
||||
});
|
||||
};
|
28
server/controllers/api/channel/data/getChannelData.js
Normal file
28
server/controllers/api/channel/data/getChannelData.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
const db = require('../../../../models');
|
||||
|
||||
const getChannelData = (channelName, channelClaimId) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let longChannelClaimId;
|
||||
// 1. get the long channel Id (make sure channel exists)
|
||||
db.Certificate
|
||||
.getLongChannelId(channelName, channelClaimId)
|
||||
.then(fullClaimId => {
|
||||
longChannelClaimId = fullClaimId;
|
||||
return db
|
||||
.Certificate
|
||||
.getShortChannelIdFromLongChannelId(fullClaimId, channelName);
|
||||
})
|
||||
.then(shortChannelClaimId => {
|
||||
resolve({
|
||||
channelName,
|
||||
longChannelClaimId,
|
||||
shortChannelClaimId,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = getChannelData;
|
|
@ -1,5 +1,6 @@
|
|||
const { getChannelData } = require('../../controllers/serveController.js');
|
||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
|
||||
const getChannelData = require('./getChannelData.js');
|
||||
|
||||
const NO_CHANNEL = 'NO_CHANNEL';
|
||||
|
||||
|
@ -13,14 +14,20 @@ const channelData = ({ ip, originalUrl, body, params }, res) => {
|
|||
const channelName = params.channelName;
|
||||
let channelClaimId = params.channelClaimId;
|
||||
if (channelClaimId === 'none') channelClaimId = null;
|
||||
getChannelData(channelName, channelClaimId, 0)
|
||||
getChannelData(channelName, channelClaimId)
|
||||
.then(data => {
|
||||
if (data === NO_CHANNEL) {
|
||||
return res.status(404).json({success: false, message: 'No matching channel was found'});
|
||||
}
|
||||
res.status(200).json({success: true, data});
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
data
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
if (error === NO_CHANNEL) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'No matching channel was found',
|
||||
});
|
||||
}
|
||||
handleErrorResponse(originalUrl, ip, error, res);
|
||||
});
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
||||
const db = require('../../models');
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
const db = require('../../../../models');
|
||||
|
||||
/*
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
const db = require('../../../../models/index');
|
||||
const { publishing: { primaryClaimAddress, additionalClaimAddresses } } = require('../../../../../config/siteConfig.js');
|
||||
const Sequelize = require('sequelize');
|
||||
const Op = Sequelize.Op;
|
||||
|
||||
const claimAvailability = (name) => {
|
||||
const claimAddresses = additionalClaimAddresses || [];
|
||||
claimAddresses.push(primaryClaimAddress);
|
||||
// find any records where the name is used
|
||||
return db.Claim
|
||||
.findAll({
|
||||
attributes: ['address'],
|
||||
where : {
|
||||
name,
|
||||
address: {
|
||||
[Op.or]: claimAddresses,
|
||||
},
|
||||
},
|
||||
})
|
||||
.then(result => {
|
||||
if (result.length >= 1) {
|
||||
throw new Error('That claim is already in use');
|
||||
}
|
||||
return name;
|
||||
})
|
||||
.catch(error => {
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = claimAvailability;
|
|
@ -1,6 +1,6 @@
|
|||
const { claimNameIsAvailable } = require('../../controllers/publishController.js');
|
||||
const { sendGATimingEvent } = require('../../helpers/googleAnalytics.js');
|
||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
||||
const checkClaimAvailability = require('./checkClaimAvailability.js');
|
||||
const { sendGATimingEvent } = require('../../../../utils/googleAnalytics.js');
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
|
||||
/*
|
||||
|
||||
|
@ -10,7 +10,7 @@ const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
|||
|
||||
const claimAvailability = ({ ip, originalUrl, params: { name } }, res) => {
|
||||
const gaStartTime = Date.now();
|
||||
claimNameIsAvailable(name)
|
||||
checkClaimAvailability(name)
|
||||
.then(result => {
|
||||
res.status(200).json(result);
|
||||
sendGATimingEvent('end-to-end', 'claim name availability', name, gaStartTime, Date.now());
|
56
server/controllers/api/claim/blockedList/index.js
Normal file
56
server/controllers/api/claim/blockedList/index.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
const logger = require('winston');
|
||||
const db = require('../../../../models');
|
||||
|
||||
const updateBlockedList = (req, res) => {
|
||||
return fetch('https://api.lbry.io/file/list_blocked')
|
||||
.then(response => {
|
||||
return response.json();
|
||||
})
|
||||
.then(jsonResponse => {
|
||||
if (!jsonResponse.data) {
|
||||
throw new Error('no data in list_blocked response');
|
||||
}
|
||||
if (!jsonResponse.data.outpoints) {
|
||||
throw new Error('no outpoints in list_blocked response');
|
||||
}
|
||||
return jsonResponse.data.outpoints;
|
||||
})
|
||||
.then(outpoints => {
|
||||
logger.info('number of blocked outpoints:', outpoints.length);
|
||||
let updatePromises = [];
|
||||
outpoints.forEach(outpoint => {
|
||||
// logger.debug('outpoint:', outpoint);
|
||||
updatePromises.push(db.Claim
|
||||
.findOne({
|
||||
where: {
|
||||
outpoint,
|
||||
},
|
||||
})
|
||||
.then(Claim => {
|
||||
if (Claim) {
|
||||
const { claimId, name } = Claim;
|
||||
logger.debug(`creating record in Blocked for ${name}#${claimId}`);
|
||||
const blocked = {
|
||||
claimId,
|
||||
name,
|
||||
outpoint,
|
||||
};
|
||||
return db.upsert(db.Blocked, blocked, blocked, 'Blocked')
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error(error);
|
||||
}));
|
||||
});
|
||||
return Promise.all(updatePromises);
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('finished updating blocked content list');
|
||||
res.status(200).json({success: true, message: 'finished updating blocked content list'});
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = updateBlockedList;
|
|
@ -1,5 +1,5 @@
|
|||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
||||
const db = require('../../models');
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
const db = require('../../../../models');
|
||||
|
||||
/*
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = (fileInfo, getResult) => {
|
||||
fileInfo.fileName = getResult.file_name;
|
||||
fileInfo.filePath = getResult.download_path;
|
||||
return fileInfo;
|
||||
};
|
13
server/controllers/api/claim/get/createFileData.js
Normal file
13
server/controllers/api/claim/get/createFileData.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
module.exports = ({ name, claimId, outpoint, height, address, nsfw, contentType }) => {
|
||||
return {
|
||||
name,
|
||||
claimId,
|
||||
outpoint,
|
||||
height,
|
||||
address,
|
||||
fileName: '',
|
||||
filePath: '',
|
||||
fileType: contentType,
|
||||
nsfw,
|
||||
};
|
||||
};
|
|
@ -1,7 +1,8 @@
|
|||
const { getClaim } = require('../../helpers/lbryApi.js');
|
||||
const { addGetResultsToFileData, createFileData } = require('../../helpers/publishHelpers.js');
|
||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
||||
const db = require('../../models');
|
||||
const { getClaim } = require('../../../../lbrynet');
|
||||
const addGetResultsToFileData = require('./addGetResultsToFileData.js');
|
||||
const createFileData = require('./createFileData.js');
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
const db = require('../../../../models');
|
||||
|
||||
/*
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
const { getClaimList } = require('../../helpers/lbryApi.js');
|
||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
||||
const { getClaimList } = require('../../../../lbrynet');
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
|
||||
/*
|
||||
|
31
server/controllers/api/claim/longId/getClaimId.js
Normal file
31
server/controllers/api/claim/longId/getClaimId.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
const logger = require('winston');
|
||||
|
||||
const db = require('../../../../models');
|
||||
|
||||
const getClaimIdByChannel = (channelName, channelClaimId, claimName) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.Certificate
|
||||
.getLongChannelId(channelName, channelClaimId)
|
||||
.then(longChannelId => {
|
||||
return db.Claim.getClaimIdByLongChannelId(longChannelId, claimName);
|
||||
})
|
||||
.then(longClaimId => {
|
||||
resolve(longClaimId);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const getClaimId = (channelName, channelClaimId, name, claimId) => {
|
||||
if (channelName) {
|
||||
logger.debug(`getClaimIdByChannel(${channelName}, ${channelClaimId}, ${name})`);
|
||||
return getClaimIdByChannel(channelName, channelClaimId, name);
|
||||
} else {
|
||||
logger.debug(`db.Claim.getLongClaimId(${name}, ${claimId})`);
|
||||
return db.Claim.getLongClaimId(name, claimId);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = getClaimId;
|
53
server/controllers/api/claim/longId/index.js
Normal file
53
server/controllers/api/claim/longId/index.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
const db = require('../../../../models');
|
||||
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
|
||||
const getClaimId = require('./getClaimId.js');
|
||||
|
||||
const NO_CHANNEL = 'NO_CHANNEL';
|
||||
const NO_CLAIM = 'NO_CLAIM';
|
||||
const BLOCKED_CLAIM = 'BLOCKED_CLAIM';
|
||||
|
||||
/*
|
||||
|
||||
route to get a long claim id
|
||||
|
||||
*/
|
||||
|
||||
const claimLongId = ({ ip, originalUrl, body, params }, res) => {
|
||||
const channelName = body.channelName;
|
||||
const channelClaimId = body.channelClaimId;
|
||||
const claimName = body.claimName;
|
||||
let claimId = body.claimId;
|
||||
getClaimId(channelName, channelClaimId, claimName, claimId)
|
||||
.then(fullClaimId => {
|
||||
claimId = fullClaimId;
|
||||
return db.Blocked.isNotBlocked(fullClaimId, claimName);
|
||||
})
|
||||
.then(() => {
|
||||
res.status(200).json({success: true, data: claimId});
|
||||
})
|
||||
.catch(error => {
|
||||
if (error === NO_CLAIM) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'No matching claim id could be found for that url',
|
||||
});
|
||||
}
|
||||
if (error === NO_CHANNEL) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'No matching channel id could be found for that url',
|
||||
});
|
||||
}
|
||||
if (error === BLOCKED_CLAIM) {
|
||||
return res.status(410).json({
|
||||
success: false,
|
||||
message: 'In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications. For more details, see https://lbry.io/faq/dmca',
|
||||
});
|
||||
}
|
||||
handleErrorResponse(originalUrl, ip, error, res);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = claimLongId;
|
75
server/controllers/api/claim/publish/authentication.js
Normal file
75
server/controllers/api/claim/publish/authentication.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
const logger = require('winston');
|
||||
const db = require('../../../../models/index');
|
||||
|
||||
const authenticateChannelCredentials = (channelName, channelId, userPassword) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// hoisted variables
|
||||
let channelData;
|
||||
// build the params for finding the channel
|
||||
let channelFindParams = {};
|
||||
if (channelName) channelFindParams['channelName'] = channelName;
|
||||
if (channelId) channelFindParams['channelClaimId'] = channelId;
|
||||
// find the channel
|
||||
db.Channel
|
||||
.findOne({
|
||||
where: channelFindParams,
|
||||
})
|
||||
.then(channel => {
|
||||
if (!channel) {
|
||||
logger.debug('no channel found');
|
||||
throw new Error('Authentication failed, you do not have access to that channel');
|
||||
}
|
||||
channelData = channel.get();
|
||||
logger.debug('channel data:', channelData);
|
||||
return db.User.findOne({
|
||||
where: { userName: channelData.channelName.substring(1) },
|
||||
});
|
||||
})
|
||||
.then(user => {
|
||||
if (!user) {
|
||||
logger.debug('no user found');
|
||||
throw new Error('Authentication failed, you do not have access to that channel');
|
||||
}
|
||||
return user.comparePassword(userPassword);
|
||||
})
|
||||
.then(isMatch => {
|
||||
if (!isMatch) {
|
||||
logger.debug('incorrect password');
|
||||
throw new Error('Authentication failed, you do not have access to that channel');
|
||||
}
|
||||
logger.debug('...password was a match...');
|
||||
resolve(channelData);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const authenticateUser = (channelName, channelId, channelPassword, user) => {
|
||||
// case: no channelName or channel Id are provided (anonymous), regardless of whether user token is provided
|
||||
if (!channelName && !channelId) {
|
||||
return {
|
||||
channelName : null,
|
||||
channelClaimId: null,
|
||||
};
|
||||
}
|
||||
// case: channelName or channel Id are provided with user token
|
||||
if (user) {
|
||||
if (channelName && channelName !== user.channelName) {
|
||||
throw new Error('the provided channel name does not match user credentials');
|
||||
}
|
||||
if (channelId && channelId !== user.channelClaimId) {
|
||||
throw new Error('the provided channel id does not match user credentials');
|
||||
}
|
||||
return {
|
||||
channelName : user.channelName,
|
||||
channelClaimId: user.channelClaimId,
|
||||
};
|
||||
}
|
||||
// case: channelName or channel Id are provided with password instead of user token
|
||||
if (!channelPassword) throw new Error('no channel password provided');
|
||||
return authenticateChannelCredentials(channelName, channelId, channelPassword);
|
||||
};
|
||||
|
||||
module.exports = authenticateUser;
|
|
@ -0,0 +1,40 @@
|
|||
const logger = require('winston');
|
||||
const { details, publishing } = require('../../../../../config/siteConfig.js');
|
||||
|
||||
const createBasicPublishParams = (filePath, name, title, description, license, nsfw, thumbnail) => {
|
||||
logger.debug(`Creating Publish Parameters`);
|
||||
// provide defaults for title
|
||||
if (title === null || title.trim() === '') {
|
||||
title = name;
|
||||
}
|
||||
// provide default for description
|
||||
if (description === null || description.trim() === '') {
|
||||
description = '';
|
||||
}
|
||||
// provide default for license
|
||||
if (license === null || license.trim() === '') {
|
||||
license = ' '; // default to empty string
|
||||
}
|
||||
// create the publish params
|
||||
const publishParams = {
|
||||
name,
|
||||
file_path: filePath,
|
||||
bid : 0.01,
|
||||
metadata : {
|
||||
description,
|
||||
title,
|
||||
author : details.title,
|
||||
language: 'en',
|
||||
license,
|
||||
nsfw,
|
||||
},
|
||||
claim_address: publishing.primaryClaimAddress,
|
||||
};
|
||||
// add thumbnail to channel if video
|
||||
if (thumbnail) {
|
||||
publishParams['metadata']['thumbnail'] = thumbnail;
|
||||
}
|
||||
return publishParams;
|
||||
};
|
||||
|
||||
module.exports = createBasicPublishParams;
|
|
@ -0,0 +1,28 @@
|
|||
const logger = require('winston');
|
||||
const { details, publishing } = require('../../../../../config/siteConfig.js');
|
||||
|
||||
const createThumbnailPublishParams = (thumbnailFilePath, claimName, license, nsfw) => {
|
||||
if (!thumbnailFilePath) {
|
||||
return;
|
||||
}
|
||||
logger.debug(`Creating Thumbnail Publish Parameters`);
|
||||
// create the publish params
|
||||
return {
|
||||
name : `${claimName}-thumb`,
|
||||
file_path: thumbnailFilePath,
|
||||
bid : 0.01,
|
||||
metadata : {
|
||||
title : `${claimName} thumbnail`,
|
||||
description: `a thumbnail for ${claimName}`,
|
||||
author : details.title,
|
||||
language : 'en',
|
||||
license,
|
||||
nsfw,
|
||||
},
|
||||
claim_address: publishing.primaryClaimAddress,
|
||||
channel_name : publishing.thumbnailChannel,
|
||||
channel_id : publishing.thumbnailChannelId,
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = createThumbnailPublishParams;
|
13
server/controllers/api/claim/publish/deleteFile.js
Normal file
13
server/controllers/api/claim/publish/deleteFile.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
const logger = require('winston');
|
||||
const fs = require('fs');
|
||||
|
||||
const deleteFile = (filePath) => {
|
||||
fs.unlink(filePath, err => {
|
||||
if (err) {
|
||||
return logger.error(`error deleting temporary file ${filePath}`);
|
||||
}
|
||||
logger.debug(`successfully deleted ${filePath}`);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = deleteFile;
|
|
@ -1,9 +1,17 @@
|
|||
const { createBasicPublishParams, createThumbnailPublishParams, parsePublishApiRequestBody, parsePublishApiRequestFiles } = require('../../helpers/publishHelpers.js');
|
||||
const { claimNameIsAvailable, publish } = require('../../controllers/publishController.js');
|
||||
const { authenticateUser } = require('../../auth/authentication.js');
|
||||
const { sendGATimingEvent } = require('../../helpers/googleAnalytics.js');
|
||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
||||
const { details: { host } } = require('../../../config/siteConfig.js');
|
||||
const { details: { host } } = require('../../../../../config/siteConfig.js');
|
||||
|
||||
const { sendGATimingEvent } = require('../../../../utils/googleAnalytics.js');
|
||||
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
|
||||
const checkClaimAvailability = require('../availability/checkClaimAvailability.js');
|
||||
|
||||
const publish = require('./publish.js');
|
||||
const createBasicPublishParams = require('./createBasicPublishParams.js');
|
||||
const createThumbnailPublishParams = require('./createThumbnailPublishParams.js');
|
||||
const parsePublishApiRequestBody = require('./parsePublishApiRequestBody.js');
|
||||
const parsePublishApiRequestFiles = require('./parsePublishApiRequestFiles.js');
|
||||
const authenticateUser = require('./authentication.js');
|
||||
|
||||
/*
|
||||
|
||||
|
@ -29,7 +37,7 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user }, res) => {
|
|||
Promise
|
||||
.all([
|
||||
authenticateUser(channelName, channelId, channelPassword, user),
|
||||
claimNameIsAvailable(name),
|
||||
checkClaimAvailability(name),
|
||||
createBasicPublishParams(filePath, name, title, description, license, nsfw, thumbnail),
|
||||
createThumbnailPublishParams(thumbnailFilePath, name, license, nsfw),
|
||||
])
|
||||
|
@ -39,7 +47,7 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user }, res) => {
|
|||
publishParams['channel_name'] = channelName;
|
||||
publishParams['channel_id'] = channelClaimId;
|
||||
}
|
||||
// publish the thumbnail
|
||||
// publish the thumbnail, if one exists
|
||||
if (thumbnailPublishParams) {
|
||||
publish(thumbnailPublishParams, thumbnailFileName, thumbnailFileType);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
const parsePublishApiRequestBody = ({name, nsfw, license, title, description, thumbnail}) => {
|
||||
// validate name
|
||||
if (!name) {
|
||||
throw new Error('no name field found in request');
|
||||
}
|
||||
const invalidNameCharacters = /[^A-Za-z0-9,-]/.exec(name);
|
||||
if (invalidNameCharacters) {
|
||||
throw new Error('The claim name you provided is not allowed. Only the following characters are allowed: A-Z, a-z, 0-9, and "-"');
|
||||
}
|
||||
// optional parameters
|
||||
nsfw = (nsfw === 'true');
|
||||
license = license || null;
|
||||
title = title || null;
|
||||
description = description || null;
|
||||
thumbnail = thumbnail || null;
|
||||
// return results
|
||||
return {
|
||||
name,
|
||||
nsfw,
|
||||
license,
|
||||
title,
|
||||
description,
|
||||
thumbnail,
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = parsePublishApiRequestBody;
|
|
@ -0,0 +1,34 @@
|
|||
const validateFileTypeAndSize = require('./validateFileTypeAndSize.js');
|
||||
|
||||
const parsePublishApiRequestFiles = ({file, thumbnail}) => {
|
||||
// make sure a file was provided
|
||||
if (!file) {
|
||||
throw new Error('no file with key of [file] found in request');
|
||||
}
|
||||
if (!file.path) {
|
||||
throw new Error('no file path found');
|
||||
}
|
||||
if (!file.type) {
|
||||
throw new Error('no file type found');
|
||||
}
|
||||
if (!file.size) {
|
||||
throw new Error('no file type found');
|
||||
}
|
||||
// validate the file name
|
||||
if (/'/.test(file.name)) {
|
||||
throw new Error('apostrophes are not allowed in the file name');
|
||||
}
|
||||
// validate the file
|
||||
validateFileTypeAndSize(file);
|
||||
// return results
|
||||
return {
|
||||
fileName : file.name,
|
||||
filePath : file.path,
|
||||
fileType : file.type,
|
||||
thumbnailFileName: (thumbnail ? thumbnail.name : null),
|
||||
thumbnailFilePath: (thumbnail ? thumbnail.path : null),
|
||||
thumbnailFileType: (thumbnail ? thumbnail.type : null),
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = parsePublishApiRequestFiles;
|
92
server/controllers/api/claim/publish/publish.js
Normal file
92
server/controllers/api/claim/publish/publish.js
Normal file
|
@ -0,0 +1,92 @@
|
|||
const logger = require('winston');
|
||||
const db = require('../../../../models');
|
||||
const { publishClaim } = require('../../../../lbrynet');
|
||||
const deleteFile = require('./deleteFile.js');
|
||||
|
||||
const publish = (publishParams, fileName, fileType) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let publishResults, certificateId, channelName;
|
||||
// publish the file
|
||||
return publishClaim(publishParams)
|
||||
.then(tx => {
|
||||
logger.info(`Successfully published ${publishParams.name} ${fileName}`, tx);
|
||||
publishResults = tx;
|
||||
// get the channel information
|
||||
if (publishParams.channel_name) {
|
||||
logger.debug(`this claim was published in channel: ${publishParams.channel_name}`);
|
||||
return db.Channel.findOne({
|
||||
where: {
|
||||
channelName: publishParams.channel_name,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
logger.debug('this claim was not published in a channel');
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.then(channel => {
|
||||
// set channel information
|
||||
certificateId = null;
|
||||
channelName = null;
|
||||
if (channel) {
|
||||
certificateId = channel.channelClaimId;
|
||||
channelName = channel.channelName;
|
||||
}
|
||||
logger.debug(`certificateId: ${certificateId}`);
|
||||
})
|
||||
.then(() => {
|
||||
// create the File record
|
||||
const fileRecord = {
|
||||
name : publishParams.name,
|
||||
claimId : publishResults.claim_id,
|
||||
title : publishParams.metadata.title,
|
||||
description: publishParams.metadata.description,
|
||||
address : publishParams.claim_address,
|
||||
outpoint : `${publishResults.txid}:${publishResults.nout}`,
|
||||
height : 0,
|
||||
fileName,
|
||||
filePath : publishParams.file_path,
|
||||
fileType,
|
||||
nsfw : publishParams.metadata.nsfw,
|
||||
};
|
||||
// create the Claim record
|
||||
const claimRecord = {
|
||||
name : publishParams.name,
|
||||
claimId : publishResults.claim_id,
|
||||
title : publishParams.metadata.title,
|
||||
description: publishParams.metadata.description,
|
||||
address : publishParams.claim_address,
|
||||
thumbnail : publishParams.metadata.thumbnail,
|
||||
outpoint : `${publishResults.txid}:${publishResults.nout}`,
|
||||
height : 0,
|
||||
contentType: fileType,
|
||||
nsfw : publishParams.metadata.nsfw,
|
||||
amount : publishParams.bid,
|
||||
certificateId,
|
||||
channelName,
|
||||
};
|
||||
// upsert criteria
|
||||
const upsertCriteria = {
|
||||
name : publishParams.name,
|
||||
claimId: publishResults.claim_id,
|
||||
};
|
||||
// upsert the records
|
||||
return Promise.all([db.upsert(db.File, fileRecord, upsertCriteria, 'File'), db.upsert(db.Claim, claimRecord, upsertCriteria, 'Claim')]);
|
||||
})
|
||||
.then(([file, claim]) => {
|
||||
logger.debug('File and Claim records successfully created');
|
||||
return Promise.all([file.setClaim(claim), claim.setFile(file)]);
|
||||
})
|
||||
.then(() => {
|
||||
logger.debug('File and Claim records successfully associated');
|
||||
resolve(publishResults); // resolve the promise with the result from lbryApi publishClaim;
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('PUBLISH ERROR', error);
|
||||
deleteFile(publishParams.file_path); // delete the local file
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = publish;
|
|
@ -0,0 +1,33 @@
|
|||
const logger = require('winston');
|
||||
|
||||
const validateFileTypeAndSize = (file) => {
|
||||
// check file type and size
|
||||
switch (file.type) {
|
||||
case 'image/jpeg':
|
||||
case 'image/jpg':
|
||||
case 'image/png':
|
||||
if (file.size > 10000000) {
|
||||
logger.debug('publish > file validation > .jpeg/.jpg/.png was too big');
|
||||
throw new Error('Sorry, images are limited to 10 megabytes.');
|
||||
}
|
||||
break;
|
||||
case 'image/gif':
|
||||
if (file.size > 50000000) {
|
||||
logger.debug('publish > file validation > .gif was too big');
|
||||
throw new Error('Sorry, .gifs are limited to 50 megabytes.');
|
||||
}
|
||||
break;
|
||||
case 'video/mp4':
|
||||
if (file.size > 50000000) {
|
||||
logger.debug('publish > file validation > .mp4 was too big');
|
||||
throw new Error('Sorry, videos are limited to 50 megabytes.');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.debug('publish > file validation > unrecognized file type');
|
||||
throw new Error('The ' + file.type + ' content type is not supported. Only, .jpeg, .png, .gif, and .mp4 files are currently supported.');
|
||||
}
|
||||
return file;
|
||||
};
|
||||
|
||||
module.exports = validateFileTypeAndSize;
|
|
@ -1,5 +1,5 @@
|
|||
const { resolveUri } = require('../../helpers/lbryApi.js');
|
||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
||||
const { resolveUri } = require('../../../../lbrynet/index');
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
|
||||
/*
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
||||
const db = require('../../models');
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
const db = require('../../../../models');
|
||||
|
||||
/*
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
||||
const db = require('../../models');
|
||||
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||
const db = require('../../../../models');
|
||||
|
||||
/*
|
||||
|
|
@ -1,7 +1,12 @@
|
|||
const { sendGAServeEvent } = require('../../helpers/googleAnalytics');
|
||||
const { determineResponseType, logRequestData, getClaimIdAndServeAsset } = require('../../helpers/serveHelpers.js');
|
||||
const lbryUri = require('../../helpers/lbryUri.js');
|
||||
const handleShowRender = require('../../render/build/handleShowRender.js');
|
||||
const { sendGAServeEvent } = require('../../../utils/googleAnalytics');
|
||||
const handleShowRender = require('../../../render/build/handleShowRender.js');
|
||||
|
||||
const lbryUri = require('../utils/lbryUri.js');
|
||||
|
||||
const determineResponseType = require('../utils/determineResponseType.js');
|
||||
const getClaimIdAndServeAsset = require('../utils/getClaimIdAndServeAsset.js');
|
||||
const logRequestData = require('../utils/logRequestData.js');
|
||||
|
||||
const SERVE = 'SERVE';
|
||||
|
||||
/*
|
|
@ -1,12 +1,12 @@
|
|||
const { sendGAServeEvent } = require('../../helpers/googleAnalytics');
|
||||
const {
|
||||
determineResponseType,
|
||||
flipClaimNameAndIdForBackwardsCompatibility,
|
||||
logRequestData,
|
||||
getClaimIdAndServeAsset,
|
||||
} = require('../../helpers/serveHelpers.js');
|
||||
const lbryUri = require('../../helpers/lbryUri.js');
|
||||
const handleShowRender = require('../../render/build/handleShowRender.js');
|
||||
const { sendGAServeEvent } = require('../../../utils/googleAnalytics');
|
||||
const handleShowRender = require('../../../render/build/handleShowRender.js');
|
||||
|
||||
const lbryUri = require('../utils/lbryUri.js');
|
||||
|
||||
const determineResponseType = require('../utils/determineResponseType.js');
|
||||
const getClaimIdAndServeAsset = require('../utils/getClaimIdAndServeAsset.js');
|
||||
const flipClaimNameAndId = require('../utils/flipClaimNameAndId.js');
|
||||
const logRequestData = require('../utils/logRequestData.js');
|
||||
|
||||
const SERVE = 'SERVE';
|
||||
|
||||
|
@ -46,8 +46,9 @@ const serverAssetByIdentifierAndClaim = (req, res) => {
|
|||
} catch (error) {
|
||||
return res.status(400).json({success: false, message: error.message});
|
||||
}
|
||||
// for backwards compatability, flip claim name and claim id if necessary
|
||||
if (!isChannel) {
|
||||
[claimId, claimName] = flipClaimNameAndIdForBackwardsCompatibility(claimId, claimName);
|
||||
[claimId, claimName] = flipClaimNameAndId(claimId, claimName);
|
||||
}
|
||||
// log the request data for debugging
|
||||
logRequestData(responseType, claimName, channelName, claimId);
|
37
server/controllers/assets/utils/determineResponseType.js
Normal file
37
server/controllers/assets/utils/determineResponseType.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
const logger = require('winston');
|
||||
|
||||
const SERVE = 'SERVE';
|
||||
const SHOW = 'SHOW';
|
||||
|
||||
function clientAcceptsHtml ({accept}) {
|
||||
return accept && accept.match(/text\/html/);
|
||||
};
|
||||
|
||||
function requestIsFromBrowser (headers) {
|
||||
return headers['user-agent'] && headers['user-agent'].match(/Mozilla/);
|
||||
};
|
||||
|
||||
function clientWantsAsset ({accept, range}) {
|
||||
const imageIsWanted = accept && accept.match(/image\/.*/) && !accept.match(/text\/html/) && !accept.match(/text\/\*/);
|
||||
const videoIsWanted = accept && range;
|
||||
return imageIsWanted || videoIsWanted;
|
||||
};
|
||||
|
||||
const determineResponseType = (hasFileExtension, headers) => {
|
||||
let responseType;
|
||||
if (hasFileExtension) {
|
||||
responseType = SERVE; // assume a serve request if file extension is present
|
||||
if (clientAcceptsHtml(headers)) { // if the request comes from a browser, change it to a show request
|
||||
responseType = SHOW;
|
||||
}
|
||||
} else {
|
||||
responseType = SHOW;
|
||||
if (clientWantsAsset(headers) && requestIsFromBrowser(headers)) { // this is in case someone embeds a show url
|
||||
logger.debug('Show request came from browser but wants an image/video. Changing response to serve...');
|
||||
responseType = SERVE;
|
||||
}
|
||||
}
|
||||
return responseType;
|
||||
};
|
||||
|
||||
module.exports = determineResponseType;
|
23
server/controllers/assets/utils/flipClaimNameAndId.js
Normal file
23
server/controllers/assets/utils/flipClaimNameAndId.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
function isValidClaimId (claimId) {
|
||||
return ((claimId.length === 40) && !/[^A-Za-z0-9]/g.test(claimId));
|
||||
};
|
||||
|
||||
function isValidShortId (claimId) {
|
||||
return claimId.length === 1; // it should really evaluate the short url itself
|
||||
};
|
||||
|
||||
function isValidShortIdOrClaimId (input) {
|
||||
return (isValidClaimId(input) || isValidShortId(input));
|
||||
};
|
||||
|
||||
const flipClaimNameAndId = (identifier, name) => {
|
||||
// this is a patch for backwards compatability with '/name/claimId' url format
|
||||
if (isValidShortIdOrClaimId(name) && !isValidShortIdOrClaimId(identifier)) {
|
||||
const tempName = name;
|
||||
name = identifier;
|
||||
identifier = tempName;
|
||||
}
|
||||
return [identifier, name];
|
||||
};
|
||||
|
||||
module.exports = flipClaimNameAndId;
|
58
server/controllers/assets/utils/getClaimIdAndServeAsset.js
Normal file
58
server/controllers/assets/utils/getClaimIdAndServeAsset.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
const logger = require('winston');
|
||||
|
||||
const db = require('../../../models');
|
||||
|
||||
const getClaimId = require('../../api/claim/longId/getClaimId.js');
|
||||
const { handleErrorResponse } = require('../../utils/errorHandlers.js');
|
||||
|
||||
const getLocalFileRecord = require('./getLocalFileRecord.js');
|
||||
const serveFile = require('./serveFile.js');
|
||||
|
||||
const NO_CHANNEL = 'NO_CHANNEL';
|
||||
const NO_CLAIM = 'NO_CLAIM';
|
||||
const BLOCKED_CLAIM = 'BLOCKED_CLAIM';
|
||||
const NO_FILE = 'NO_FILE';
|
||||
|
||||
const getClaimIdAndServeAsset = (channelName, channelClaimId, claimName, claimId, originalUrl, ip, res) => {
|
||||
getClaimId(channelName, channelClaimId, claimName, claimId)
|
||||
.then(fullClaimId => {
|
||||
claimId = fullClaimId;
|
||||
return db.Blocked.isNotBlocked(fullClaimId, claimName);
|
||||
})
|
||||
.then(() => {
|
||||
return getLocalFileRecord(claimId, claimName);
|
||||
})
|
||||
.then(fileRecord => {
|
||||
serveFile(fileRecord, res);
|
||||
})
|
||||
.catch(error => {
|
||||
if (error === NO_CLAIM) {
|
||||
logger.debug('no claim found');
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'No matching claim id could be found for that url',
|
||||
});
|
||||
}
|
||||
if (error === NO_CHANNEL) {
|
||||
logger.debug('no channel found');
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'No matching channel id could be found for that url',
|
||||
});
|
||||
}
|
||||
if (error === BLOCKED_CLAIM) {
|
||||
logger.debug('claim was blocked');
|
||||
return res.status(451).json({
|
||||
success: false,
|
||||
message: 'In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications. For more details, see https://lbry.io/faq/dmca',
|
||||
});
|
||||
}
|
||||
if (error === NO_FILE) {
|
||||
logger.debug('claim was blocked');
|
||||
return res.status(307).redirect(`/api/claim/get/${name}/${claimId}`);
|
||||
}
|
||||
handleErrorResponse(originalUrl, ip, error, res);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = getClaimIdAndServeAsset;
|
15
server/controllers/assets/utils/getLocalFileRecord.js
Normal file
15
server/controllers/assets/utils/getLocalFileRecord.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
const db = require('../../../models');
|
||||
|
||||
const NO_FILE = 'NO_FILE';
|
||||
|
||||
const getLocalFileRecord = (claimId, name) => {
|
||||
return db.File.findOne({where: {claimId, name}})
|
||||
.then(file => {
|
||||
if (!file) {
|
||||
return NO_FILE;
|
||||
}
|
||||
return file.dataValues;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = getLocalFileRecord;
|
10
server/controllers/assets/utils/logRequestData.js
Normal file
10
server/controllers/assets/utils/logRequestData.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
const logger = require('winston');
|
||||
|
||||
const logRequestData = (responseType, claimName, channelName, claimId) => {
|
||||
logger.debug('responseType ===', responseType);
|
||||
logger.debug('claim name === ', claimName);
|
||||
logger.debug('channel name ===', channelName);
|
||||
logger.debug('claim id ===', claimId);
|
||||
};
|
||||
|
||||
module.exports = logRequestData;
|
14
server/controllers/assets/utils/serveFile.js
Normal file
14
server/controllers/assets/utils/serveFile.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
const logger = require('winston');
|
||||
|
||||
const serveFile = ({ filePath, fileType }, res) => {
|
||||
logger.verbose(`serving file: ${filePath}`);
|
||||
const sendFileOptions = {
|
||||
headers: {
|
||||
'X-Content-Type-Options': 'nosniff',
|
||||
'Content-Type' : fileType || 'image/jpeg',
|
||||
},
|
||||
};
|
||||
res.status(200).sendFile(filePath, sendFileOptions);
|
||||
};
|
||||
|
||||
module.exports = serveFile;
|
|
@ -1,4 +1,4 @@
|
|||
const speechPassport = require('../../speechPassport');
|
||||
const speechPassport = require('../../../speechPassport/index');
|
||||
|
||||
const login = (req, res, next) => {
|
||||
speechPassport.authenticate('local-login', (err, user, info) => {
|
|
@ -1,134 +0,0 @@
|
|||
const logger = require('winston');
|
||||
const db = require('../models');
|
||||
const lbryApi = require('../helpers/lbryApi.js');
|
||||
const publishHelpers = require('../helpers/publishHelpers.js');
|
||||
const { publishing: { primaryClaimAddress, additionalClaimAddresses } } = require('../../config/siteConfig.js');
|
||||
const Sequelize = require('sequelize');
|
||||
const Op = Sequelize.Op;
|
||||
|
||||
module.exports = {
|
||||
publish (publishParams, fileName, fileType) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let publishResults, certificateId, channelName;
|
||||
// publish the file
|
||||
return lbryApi.publishClaim(publishParams)
|
||||
.then(tx => {
|
||||
logger.info(`Successfully published ${publishParams.name} ${fileName}`, tx);
|
||||
publishResults = tx;
|
||||
// get the channel information
|
||||
if (publishParams.channel_name) {
|
||||
logger.debug(`this claim was published in channel: ${publishParams.channel_name}`);
|
||||
return db.Channel.findOne({
|
||||
where: {
|
||||
channelName: publishParams.channel_name,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
logger.debug('this claim was not published in a channel');
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.then(channel => {
|
||||
// set channel information
|
||||
certificateId = null;
|
||||
channelName = null;
|
||||
if (channel) {
|
||||
certificateId = channel.channelClaimId;
|
||||
channelName = channel.channelName;
|
||||
}
|
||||
logger.debug(`certificateId: ${certificateId}`);
|
||||
})
|
||||
.then(() => {
|
||||
// create the File record
|
||||
const fileRecord = {
|
||||
name : publishParams.name,
|
||||
claimId : publishResults.claim_id,
|
||||
title : publishParams.metadata.title,
|
||||
description: publishParams.metadata.description,
|
||||
address : publishParams.claim_address,
|
||||
outpoint : `${publishResults.txid}:${publishResults.nout}`,
|
||||
height : 0,
|
||||
fileName,
|
||||
filePath : publishParams.file_path,
|
||||
fileType,
|
||||
nsfw : publishParams.metadata.nsfw,
|
||||
};
|
||||
// create the Claim record
|
||||
const claimRecord = {
|
||||
name : publishParams.name,
|
||||
claimId : publishResults.claim_id,
|
||||
title : publishParams.metadata.title,
|
||||
description: publishParams.metadata.description,
|
||||
address : publishParams.claim_address,
|
||||
thumbnail : publishParams.metadata.thumbnail,
|
||||
outpoint : `${publishResults.txid}:${publishResults.nout}`,
|
||||
height : 0,
|
||||
contentType: fileType,
|
||||
nsfw : publishParams.metadata.nsfw,
|
||||
amount : publishParams.bid,
|
||||
certificateId,
|
||||
channelName,
|
||||
};
|
||||
// upsert criteria
|
||||
const upsertCriteria = {
|
||||
name : publishParams.name,
|
||||
claimId: publishResults.claim_id,
|
||||
};
|
||||
// upsert the records
|
||||
return Promise.all([db.upsert(db.File, fileRecord, upsertCriteria, 'File'), db.upsert(db.Claim, claimRecord, upsertCriteria, 'Claim')]);
|
||||
})
|
||||
.then(([file, claim]) => {
|
||||
logger.debug('File and Claim records successfully created');
|
||||
return Promise.all([file.setClaim(claim), claim.setFile(file)]);
|
||||
})
|
||||
.then(() => {
|
||||
logger.debug('File and Claim records successfully associated');
|
||||
resolve(publishResults); // resolve the promise with the result from lbryApi.publishClaim;
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('PUBLISH ERROR', error);
|
||||
publishHelpers.deleteTemporaryFile(publishParams.file_path); // delete the local file
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
},
|
||||
claimNameIsAvailable (name) {
|
||||
const claimAddresses = additionalClaimAddresses || [];
|
||||
claimAddresses.push(primaryClaimAddress);
|
||||
// find any records where the name is used
|
||||
return db.Claim
|
||||
.findAll({
|
||||
attributes: ['address'],
|
||||
where : {
|
||||
name,
|
||||
address: {
|
||||
[Op.or]: claimAddresses,
|
||||
},
|
||||
},
|
||||
})
|
||||
.then(result => {
|
||||
if (result.length >= 1) {
|
||||
throw new Error('That claim is already in use');
|
||||
};
|
||||
return name;
|
||||
})
|
||||
.catch(error => {
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
checkChannelAvailability (name) {
|
||||
return db.Channel
|
||||
.findAll({
|
||||
where: { channelName: name },
|
||||
})
|
||||
.then(result => {
|
||||
if (result.length >= 1) {
|
||||
throw new Error('That channel has already been claimed');
|
||||
}
|
||||
return name;
|
||||
})
|
||||
.catch(error => {
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
};
|
|
@ -1,117 +0,0 @@
|
|||
const db = require('../models');
|
||||
const logger = require('winston');
|
||||
const { returnPaginatedChannelClaims } = require('../helpers/channelPagination.js');
|
||||
|
||||
const NO_CHANNEL = 'NO_CHANNEL';
|
||||
const NO_CLAIM = 'NO_CLAIM';
|
||||
const NO_FILE = 'NO_FILE';
|
||||
|
||||
module.exports = {
|
||||
getClaimId (channelName, channelClaimId, name, claimId) {
|
||||
if (channelName) {
|
||||
return module.exports.getClaimIdByChannel(channelName, channelClaimId, name);
|
||||
} else {
|
||||
return module.exports.getClaimIdByClaim(name, claimId);
|
||||
}
|
||||
},
|
||||
getClaimIdByClaim (claimName, claimId) {
|
||||
logger.debug(`getClaimIdByClaim(${claimName}, ${claimId})`);
|
||||
return new Promise((resolve, reject) => {
|
||||
db.Claim.getLongClaimId(claimName, claimId)
|
||||
.then(longClaimId => {
|
||||
if (!longClaimId) {
|
||||
resolve(NO_CLAIM);
|
||||
}
|
||||
resolve(longClaimId);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
},
|
||||
getClaimIdByChannel (channelName, channelClaimId, claimName) {
|
||||
logger.debug(`getClaimIdByChannel(${channelName}, ${channelClaimId}, ${claimName})`);
|
||||
return new Promise((resolve, reject) => {
|
||||
db.Certificate.getLongChannelId(channelName, channelClaimId) // 1. get the long channel id
|
||||
.then(longChannelId => {
|
||||
if (!longChannelId) {
|
||||
return [null, null];
|
||||
}
|
||||
return Promise.all([longChannelId, db.Claim.getClaimIdByLongChannelId(longChannelId, claimName)]); // 2. get the long claim id
|
||||
})
|
||||
.then(([longChannelId, longClaimId]) => {
|
||||
if (!longChannelId) {
|
||||
return resolve(NO_CHANNEL);
|
||||
}
|
||||
if (!longClaimId) {
|
||||
return resolve(NO_CLAIM);
|
||||
}
|
||||
resolve(longClaimId);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
},
|
||||
getChannelData (channelName, channelClaimId, page) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 1. get the long channel Id (make sure channel exists)
|
||||
db.Certificate.getLongChannelId(channelName, channelClaimId)
|
||||
.then(longChannelClaimId => {
|
||||
if (!longChannelClaimId) {
|
||||
return [null, null, null];
|
||||
}
|
||||
// 2. get the short ID and all claims for that channel
|
||||
return Promise.all([longChannelClaimId, db.Certificate.getShortChannelIdFromLongChannelId(longChannelClaimId, channelName)]);
|
||||
})
|
||||
.then(([longChannelClaimId, shortChannelClaimId]) => {
|
||||
if (!longChannelClaimId) {
|
||||
return resolve(NO_CHANNEL);
|
||||
}
|
||||
// 3. return all the channel information
|
||||
resolve({
|
||||
channelName,
|
||||
longChannelClaimId,
|
||||
shortChannelClaimId,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
},
|
||||
getChannelClaims (channelName, channelClaimId, page) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 1. get the long channel Id (make sure channel exists)
|
||||
db.Certificate.getLongChannelId(channelName, channelClaimId)
|
||||
.then(longChannelClaimId => {
|
||||
if (!longChannelClaimId) {
|
||||
return [null, null, null];
|
||||
}
|
||||
// 2. get the short ID and all claims for that channel
|
||||
return Promise.all([longChannelClaimId, db.Claim.getAllChannelClaims(longChannelClaimId)]);
|
||||
})
|
||||
.then(([longChannelClaimId, channelClaimsArray]) => {
|
||||
if (!longChannelClaimId) {
|
||||
return resolve(NO_CHANNEL);
|
||||
}
|
||||
// 3. format the data for the view, including pagination
|
||||
let paginatedChannelViewData = returnPaginatedChannelClaims(channelName, longChannelClaimId, channelClaimsArray, page);
|
||||
// 4. return all the channel information and contents
|
||||
resolve(paginatedChannelViewData);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
},
|
||||
getLocalFileRecord (claimId, name) {
|
||||
return db.File.findOne({where: {claimId, name}})
|
||||
.then(file => {
|
||||
if (!file) {
|
||||
return NO_FILE;
|
||||
}
|
||||
return file.dataValues;
|
||||
});
|
||||
},
|
||||
};
|
|
@ -1,19 +0,0 @@
|
|||
const logger = require('winston');
|
||||
const db = require('../models');
|
||||
|
||||
module.exports = {
|
||||
getRecentClaims () {
|
||||
logger.debug('retrieving most recent claims');
|
||||
return new Promise((resolve, reject) => {
|
||||
// get the raw requests data
|
||||
db.File.getRecentClaims()
|
||||
.then(results => {
|
||||
resolve(results);
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('sequelize error', error);
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
|
@ -21,8 +21,8 @@ module.exports = {
|
|||
message = error.message;
|
||||
} else {
|
||||
message = error;
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
return [status, message];
|
||||
},
|
||||
useObjectPropertiesIfNoKeys: function (err) {
|
|
@ -1,10 +0,0 @@
|
|||
module.exports = {
|
||||
serializeSpeechUser (user, done) { // returns user data to be serialized into session
|
||||
console.log('serializing user');
|
||||
done(null, user);
|
||||
},
|
||||
deserializeSpeechUser (user, done) { // deserializes session and populates additional info to req.user
|
||||
console.log('deserializing user');
|
||||
done(null, user);
|
||||
},
|
||||
};
|
|
@ -1,17 +0,0 @@
|
|||
const logger = require('winston');
|
||||
|
||||
module.exports = (config) => {
|
||||
// get the config file
|
||||
for (let configCategoryKey in config) {
|
||||
if (config.hasOwnProperty(configCategoryKey)) {
|
||||
// get the final variables for each config category
|
||||
const configVariables = config[configCategoryKey];
|
||||
for (let configVarKey in configVariables) {
|
||||
if (configVariables.hasOwnProperty(configVarKey)) {
|
||||
// print each variable
|
||||
logger.debug(`CONFIG CHECK: ${configCategoryKey}.${configVarKey} === ${configVariables[configVarKey]}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,176 +0,0 @@
|
|||
const logger = require('winston');
|
||||
const fs = require('fs');
|
||||
|
||||
const { details, publishing } = require('../../config/siteConfig.js');
|
||||
|
||||
module.exports = {
|
||||
parsePublishApiRequestBody ({name, nsfw, license, title, description, thumbnail}) {
|
||||
// validate name
|
||||
if (!name) {
|
||||
throw new Error('no name field found in request');
|
||||
}
|
||||
const invalidNameCharacters = /[^A-Za-z0-9,-]/.exec(name);
|
||||
if (invalidNameCharacters) {
|
||||
throw new Error('The claim name you provided is not allowed. Only the following characters are allowed: A-Z, a-z, 0-9, and "-"');
|
||||
}
|
||||
// optional parameters
|
||||
nsfw = (nsfw === 'true');
|
||||
license = license || null;
|
||||
title = title || null;
|
||||
description = description || null;
|
||||
thumbnail = thumbnail || null;
|
||||
// return results
|
||||
return {
|
||||
name,
|
||||
nsfw,
|
||||
license,
|
||||
title,
|
||||
description,
|
||||
thumbnail,
|
||||
};
|
||||
},
|
||||
parsePublishApiRequestFiles ({file, thumbnail}) {
|
||||
// make sure a file was provided
|
||||
if (!file) {
|
||||
throw new Error('no file with key of [file] found in request');
|
||||
}
|
||||
if (!file.path) {
|
||||
throw new Error('no file path found');
|
||||
}
|
||||
if (!file.type) {
|
||||
throw new Error('no file type found');
|
||||
}
|
||||
if (!file.size) {
|
||||
throw new Error('no file type found');
|
||||
}
|
||||
// validate the file name
|
||||
if (/'/.test(file.name)) {
|
||||
throw new Error('apostrophes are not allowed in the file name');
|
||||
}
|
||||
// validate the file
|
||||
module.exports.validateFileTypeAndSize(file);
|
||||
// return results
|
||||
return {
|
||||
fileName : file.name,
|
||||
filePath : file.path,
|
||||
fileType : file.type,
|
||||
thumbnailFileName: (thumbnail ? thumbnail.name : null),
|
||||
thumbnailFilePath: (thumbnail ? thumbnail.path : null),
|
||||
thumbnailFileType: (thumbnail ? thumbnail.type : null),
|
||||
};
|
||||
},
|
||||
validateFileTypeAndSize (file) {
|
||||
// check file type and size
|
||||
switch (file.type) {
|
||||
case 'image/jpeg':
|
||||
case 'image/jpg':
|
||||
case 'image/png':
|
||||
if (file.size > 10000000) {
|
||||
logger.debug('publish > file validation > .jpeg/.jpg/.png was too big');
|
||||
throw new Error('Sorry, images are limited to 10 megabytes.');
|
||||
}
|
||||
break;
|
||||
case 'image/gif':
|
||||
if (file.size > 50000000) {
|
||||
logger.debug('publish > file validation > .gif was too big');
|
||||
throw new Error('Sorry, .gifs are limited to 50 megabytes.');
|
||||
}
|
||||
break;
|
||||
case 'video/mp4':
|
||||
if (file.size > 50000000) {
|
||||
logger.debug('publish > file validation > .mp4 was too big');
|
||||
throw new Error('Sorry, videos are limited to 50 megabytes.');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.debug('publish > file validation > unrecognized file type');
|
||||
throw new Error('The ' + file.type + ' content type is not supported. Only, .jpeg, .png, .gif, and .mp4 files are currently supported.');
|
||||
}
|
||||
return file;
|
||||
},
|
||||
createBasicPublishParams (filePath, name, title, description, license, nsfw, thumbnail) {
|
||||
logger.debug(`Creating Publish Parameters`);
|
||||
// provide defaults for title
|
||||
if (title === null || title.trim() === '') {
|
||||
title = name;
|
||||
}
|
||||
// provide default for description
|
||||
if (description === null || description.trim() === '') {
|
||||
description = '';
|
||||
}
|
||||
// provide default for license
|
||||
if (license === null || license.trim() === '') {
|
||||
license = ' '; // default to empty string
|
||||
}
|
||||
// create the publish params
|
||||
const publishParams = {
|
||||
name,
|
||||
file_path: filePath,
|
||||
bid : 0.01,
|
||||
metadata : {
|
||||
description,
|
||||
title,
|
||||
author : details.title,
|
||||
language: 'en',
|
||||
license,
|
||||
nsfw,
|
||||
},
|
||||
claim_address: publishing.primaryClaimAddress,
|
||||
};
|
||||
// add thumbnail to channel if video
|
||||
if (thumbnail) {
|
||||
publishParams['metadata']['thumbnail'] = thumbnail;
|
||||
}
|
||||
return publishParams;
|
||||
},
|
||||
createThumbnailPublishParams (thumbnailFilePath, claimName, license, nsfw) {
|
||||
if (!thumbnailFilePath) {
|
||||
return;
|
||||
}
|
||||
logger.debug(`Creating Thumbnail Publish Parameters`);
|
||||
// create the publish params
|
||||
return {
|
||||
name : `${claimName}-thumb`,
|
||||
file_path: thumbnailFilePath,
|
||||
bid : 0.01,
|
||||
metadata : {
|
||||
title : `${claimName} thumbnail`,
|
||||
description: `a thumbnail for ${claimName}`,
|
||||
author : details.title,
|
||||
language : 'en',
|
||||
license,
|
||||
nsfw,
|
||||
},
|
||||
claim_address: publishing.primaryClaimAddress,
|
||||
channel_name : publishing.thumbnailChannel,
|
||||
channel_id : publishing.thumbnailChannelId,
|
||||
};
|
||||
},
|
||||
deleteTemporaryFile (filePath) {
|
||||
fs.unlink(filePath, err => {
|
||||
if (err) {
|
||||
logger.error(`error deleting temporary file ${filePath}`);
|
||||
throw err;
|
||||
}
|
||||
logger.debug(`successfully deleted ${filePath}`);
|
||||
});
|
||||
},
|
||||
addGetResultsToFileData (fileInfo, getResult) {
|
||||
fileInfo.fileName = getResult.file_name;
|
||||
fileInfo.filePath = getResult.download_path;
|
||||
return fileInfo;
|
||||
},
|
||||
createFileData ({ name, claimId, outpoint, height, address, nsfw, contentType }) {
|
||||
return {
|
||||
name,
|
||||
claimId,
|
||||
outpoint,
|
||||
height,
|
||||
address,
|
||||
fileName: '',
|
||||
filePath: '',
|
||||
fileType: contentType,
|
||||
nsfw,
|
||||
};
|
||||
},
|
||||
};
|
|
@ -1,25 +0,0 @@
|
|||
module.exports = {
|
||||
returnShortId: function (claimsArray, longId) {
|
||||
let claimIndex;
|
||||
let shortId = longId.substring(0, 1); // default short id is the first letter
|
||||
let shortIdLength = 0;
|
||||
// find the index of this claim id
|
||||
claimIndex = claimsArray.findIndex(element => {
|
||||
return element.claimId === longId;
|
||||
});
|
||||
if (claimIndex < 0) {
|
||||
throw new Error('claim id not found in claims list');
|
||||
}
|
||||
// get an array of all claims with lower height
|
||||
let possibleMatches = claimsArray.slice(0, claimIndex);
|
||||
// remove certificates with the same prefixes until none are left.
|
||||
while (possibleMatches.length > 0) {
|
||||
shortIdLength += 1;
|
||||
shortId = longId.substring(0, shortIdLength);
|
||||
possibleMatches = possibleMatches.filter(element => {
|
||||
return (element.claimId && (element.claimId.substring(0, shortIdLength) === shortId));
|
||||
});
|
||||
}
|
||||
return shortId;
|
||||
},
|
||||
};
|
|
@ -1,109 +0,0 @@
|
|||
const logger = require('winston');
|
||||
const { getClaimId, getLocalFileRecord } = require('../controllers/serveController.js');
|
||||
const { handleErrorResponse } = require('./errorHandlers.js');
|
||||
|
||||
const SERVE = 'SERVE';
|
||||
const SHOW = 'SHOW';
|
||||
const NO_FILE = 'NO_FILE';
|
||||
const NO_CHANNEL = 'NO_CHANNEL';
|
||||
const NO_CLAIM = 'NO_CLAIM';
|
||||
|
||||
function clientAcceptsHtml ({accept}) {
|
||||
return accept && accept.match(/text\/html/);
|
||||
};
|
||||
|
||||
function requestIsFromBrowser (headers) {
|
||||
return headers['user-agent'] && headers['user-agent'].match(/Mozilla/);
|
||||
};
|
||||
|
||||
function clientWantsAsset ({accept, range}) {
|
||||
const imageIsWanted = accept && accept.match(/image\/.*/) && !accept.match(/text\/html/) && !accept.match(/text\/\*/);
|
||||
const videoIsWanted = accept && range;
|
||||
return imageIsWanted || videoIsWanted;
|
||||
};
|
||||
|
||||
function isValidClaimId (claimId) {
|
||||
return ((claimId.length === 40) && !/[^A-Za-z0-9]/g.test(claimId));
|
||||
};
|
||||
|
||||
function isValidShortId (claimId) {
|
||||
return claimId.length === 1; // it should really evaluate the short url itself
|
||||
};
|
||||
|
||||
function isValidShortIdOrClaimId (input) {
|
||||
return (isValidClaimId(input) || isValidShortId(input));
|
||||
};
|
||||
|
||||
function serveAssetToClient (claimId, name, res) {
|
||||
return getLocalFileRecord(claimId, name)
|
||||
.then(fileRecord => {
|
||||
// check that a local record was found
|
||||
if (fileRecord === NO_FILE) {
|
||||
return res.status(307).redirect(`/api/claim/get/${name}/${claimId}`);
|
||||
}
|
||||
// serve the file
|
||||
const {filePath, fileType} = fileRecord;
|
||||
logger.verbose(`serving file: ${filePath}`);
|
||||
const sendFileOptions = {
|
||||
headers: {
|
||||
'X-Content-Type-Options': 'nosniff',
|
||||
'Content-Type' : fileType || 'image/jpeg',
|
||||
},
|
||||
};
|
||||
res.status(200).sendFile(filePath, sendFileOptions);
|
||||
})
|
||||
.catch(error => {
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getClaimIdAndServeAsset (channelName, channelClaimId, claimName, claimId, originalUrl, ip, res) {
|
||||
// get the claim Id and then serve the asset
|
||||
getClaimId(channelName, channelClaimId, claimName, claimId)
|
||||
.then(fullClaimId => {
|
||||
if (fullClaimId === NO_CLAIM) {
|
||||
return res.status(404).json({success: false, message: 'no claim id could be found'});
|
||||
} else if (fullClaimId === NO_CHANNEL) {
|
||||
return res.status(404).json({success: false, message: 'no channel id could be found'});
|
||||
}
|
||||
serveAssetToClient(fullClaimId, claimName, res);
|
||||
// postToStats(responseType, originalUrl, ip, claimName, fullClaimId, 'success');
|
||||
})
|
||||
.catch(error => {
|
||||
handleErrorResponse(originalUrl, ip, error, res);
|
||||
// postToStats(responseType, originalUrl, ip, claimName, fullClaimId, 'fail');
|
||||
});
|
||||
},
|
||||
determineResponseType (hasFileExtension, headers) {
|
||||
let responseType;
|
||||
if (hasFileExtension) {
|
||||
responseType = SERVE; // assume a serve request if file extension is present
|
||||
if (clientAcceptsHtml(headers)) { // if the request comes from a browser, change it to a show request
|
||||
responseType = SHOW;
|
||||
}
|
||||
} else {
|
||||
responseType = SHOW;
|
||||
if (clientWantsAsset(headers) && requestIsFromBrowser(headers)) { // this is in case someone embeds a show url
|
||||
logger.debug('Show request came from browser but wants an image/video. Changing response to serve...');
|
||||
responseType = SERVE;
|
||||
}
|
||||
}
|
||||
return responseType;
|
||||
},
|
||||
flipClaimNameAndIdForBackwardsCompatibility (identifier, name) {
|
||||
// this is a patch for backwards compatability with '/name/claim_id' url format
|
||||
if (isValidShortIdOrClaimId(name) && !isValidShortIdOrClaimId(identifier)) {
|
||||
const tempName = name;
|
||||
name = identifier;
|
||||
identifier = tempName;
|
||||
}
|
||||
return [identifier, name];
|
||||
},
|
||||
logRequestData (responseType, claimName, channelName, claimId) {
|
||||
logger.debug('responseType ===', responseType);
|
||||
logger.debug('claim name === ', claimName);
|
||||
logger.debug('channel name ===', channelName);
|
||||
logger.debug('claim id ===', claimId);
|
||||
},
|
||||
};
|
|
@ -1,38 +0,0 @@
|
|||
const logger = require('winston');
|
||||
const db = require('../models');
|
||||
|
||||
module.exports = {
|
||||
postToStats (action, url, ipAddress, name, claimId, result) {
|
||||
logger.debug('action:', action);
|
||||
// make sure the result is a string
|
||||
if (result && (typeof result !== 'string')) {
|
||||
result = result.toString();
|
||||
}
|
||||
// make sure the ip address(es) are a string
|
||||
if (ipAddress && (typeof ipAddress !== 'string')) {
|
||||
ipAddress = ipAddress.toString();
|
||||
}
|
||||
db.File
|
||||
.findOne({where: { name, claimId }})
|
||||
.then(file => {
|
||||
// create record in the db
|
||||
let FileId;
|
||||
if (file) {
|
||||
FileId = file.dataValues.id;
|
||||
} else {
|
||||
FileId = null;
|
||||
}
|
||||
return db.Request
|
||||
.create({
|
||||
action,
|
||||
url,
|
||||
ipAddress,
|
||||
result,
|
||||
FileId,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('Sequelize error >>', error);
|
||||
});
|
||||
},
|
||||
};
|
|
@ -1,24 +1,9 @@
|
|||
const axios = require('axios');
|
||||
const logger = require('winston');
|
||||
const { api: { apiHost, apiPort } } = require('../../config/lbryConfig.js');
|
||||
const lbryApiUri = 'http://' + apiHost + ':' + apiPort;
|
||||
const { chooseGaLbrynetPublishLabel, sendGATimingEvent } = require('./googleAnalytics.js');
|
||||
|
||||
const handleLbrynetResponse = ({ data }, resolve, reject) => {
|
||||
logger.debug('lbry api data:', data);
|
||||
if (data.result) {
|
||||
// check for an error
|
||||
if (data.result.error) {
|
||||
logger.debug('Lbrynet api error:', data.result.error);
|
||||
reject(new Error(data.result.error));
|
||||
return;
|
||||
};
|
||||
resolve(data.result);
|
||||
return;
|
||||
}
|
||||
// fallback in case it just timed out
|
||||
reject(JSON.stringify(data));
|
||||
};
|
||||
const lbrynetUri = 'http://' + apiHost + ':' + apiPort;
|
||||
const { chooseGaLbrynetPublishLabel, sendGATimingEvent } = require('../utils/googleAnalytics.js');
|
||||
const handleLbrynetResponse = require('./utils/handleLbrynetResponse.js');
|
||||
|
||||
module.exports = {
|
||||
publishClaim (publishParams) {
|
||||
|
@ -26,7 +11,7 @@ module.exports = {
|
|||
const gaStartTime = Date.now();
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post(lbryApiUri, {
|
||||
.post(lbrynetUri, {
|
||||
method: 'publish',
|
||||
params: publishParams,
|
||||
})
|
||||
|
@ -44,7 +29,7 @@ module.exports = {
|
|||
const gaStartTime = Date.now();
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post(lbryApiUri, {
|
||||
.post(lbrynetUri, {
|
||||
method: 'get',
|
||||
params: { uri, timeout: 20 },
|
||||
})
|
||||
|
@ -62,7 +47,7 @@ module.exports = {
|
|||
const gaStartTime = Date.now();
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post(lbryApiUri, {
|
||||
.post(lbrynetUri, {
|
||||
method: 'claim_list',
|
||||
params: { name: claimName },
|
||||
})
|
||||
|
@ -80,7 +65,7 @@ module.exports = {
|
|||
const gaStartTime = Date.now();
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post(lbryApiUri, {
|
||||
.post(lbrynetUri, {
|
||||
method: 'resolve',
|
||||
params: { uri },
|
||||
})
|
||||
|
@ -102,7 +87,7 @@ module.exports = {
|
|||
const gaStartTime = Date.now();
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post(lbryApiUri, {
|
||||
.post(lbrynetUri, {
|
||||
method: 'settings_get',
|
||||
})
|
||||
.then(({ data }) => {
|
||||
|
@ -124,7 +109,7 @@ module.exports = {
|
|||
const gaStartTime = Date.now();
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post(lbryApiUri, {
|
||||
.post(lbrynetUri, {
|
||||
method: 'channel_new',
|
||||
params: {
|
||||
channel_name: name,
|
19
server/lbrynet/utils/handleLbrynetResponse.js
Normal file
19
server/lbrynet/utils/handleLbrynetResponse.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
const logger = require('winston');
|
||||
|
||||
const handleLbrynetResponse = ({ data }, resolve, reject) => {
|
||||
logger.debug('lbry api data:', data);
|
||||
if (data.result) {
|
||||
// check for an error
|
||||
if (data.result.error) {
|
||||
logger.debug('Lbrynet api error:', data.result.error);
|
||||
reject(new Error(data.result.error));
|
||||
return;
|
||||
};
|
||||
resolve(data.result);
|
||||
return;
|
||||
}
|
||||
// fallback in case it just timed out
|
||||
reject(JSON.stringify(data));
|
||||
};
|
||||
|
||||
module.exports = handleLbrynetResponse;
|
50
server/models/blocked.js
Normal file
50
server/models/blocked.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
const logger = require('winston');
|
||||
|
||||
const BLOCKED_CLAIM = 'BLOCKED_CLAIM';
|
||||
|
||||
module.exports = (sequelize, { STRING }) => {
|
||||
const Blocked = sequelize.define(
|
||||
'Blocked',
|
||||
{
|
||||
claimId: {
|
||||
type : STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
name: {
|
||||
type : STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
outpoint: {
|
||||
type : STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
freezeTableName: true,
|
||||
}
|
||||
);
|
||||
|
||||
Blocked.isNotBlocked = function (claimId, name) {
|
||||
logger.debug(`checking to see if ${name}#${claimId} is not blocked`);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.findOne({
|
||||
where: {
|
||||
claimId,
|
||||
name,
|
||||
},
|
||||
})
|
||||
.then(result => {
|
||||
if (result) {
|
||||
return reject(BLOCKED_CLAIM);
|
||||
}
|
||||
resolve(true);
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error(error);
|
||||
reject(BLOCKED_CLAIM);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return Blocked;
|
||||
};
|
|
@ -1,5 +1,15 @@
|
|||
const logger = require('winston');
|
||||
const { returnShortId } = require('../helpers/sequelizeHelpers.js');
|
||||
const returnShortId = require('./utils/returnShortId.js');
|
||||
|
||||
const NO_CHANNEL = 'NO_CHANNEL';
|
||||
|
||||
function isLongChannelId (channelId) {
|
||||
return (channelId && (channelId.length === 40));
|
||||
}
|
||||
|
||||
function isShortChannelId (channelId) {
|
||||
return (channelId && (channelId.length < 40));
|
||||
}
|
||||
|
||||
module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
||||
const Certificate = sequelize.define(
|
||||
|
@ -110,7 +120,7 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
|||
.then(result => {
|
||||
switch (result.length) {
|
||||
case 0:
|
||||
throw new Error('No channel(s) found with that channel name');
|
||||
return reject(NO_CHANNEL);
|
||||
default:
|
||||
return resolve(returnShortId(result, longChannelId));
|
||||
}
|
||||
|
@ -121,6 +131,25 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
|||
});
|
||||
};
|
||||
|
||||
Certificate.validateLongChannelId = function (name, claimId) {
|
||||
logger.debug(`validateLongChannelId(${name}, ${claimId})`);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.findOne({
|
||||
where: {name, claimId},
|
||||
})
|
||||
.then(result => {
|
||||
if (!result) {
|
||||
return reject(NO_CHANNEL);
|
||||
}
|
||||
resolve(claimId);
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error(error);
|
||||
reject(NO_CHANNEL);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Certificate.getLongChannelIdFromShortChannelId = function (channelName, channelClaimId) {
|
||||
logger.debug(`getLongChannelIdFromShortChannelId(${channelName}, ${channelClaimId})`);
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -137,13 +166,14 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
|||
.then(result => {
|
||||
switch (result.length) {
|
||||
case 0:
|
||||
return resolve(null);
|
||||
default: // note results must be sorted
|
||||
return reject(NO_CHANNEL);
|
||||
default:
|
||||
return resolve(result[0].claimId);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
logger.error(error);
|
||||
reject(NO_CHANNEL);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -159,43 +189,26 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
|||
.then(result => {
|
||||
switch (result.length) {
|
||||
case 0:
|
||||
return resolve(null);
|
||||
return reject(NO_CHANNEL);
|
||||
default:
|
||||
return resolve(result[0].claimId);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Certificate.validateLongChannelId = function (name, claimId) {
|
||||
logger.debug(`validateLongChannelId(${name}, ${claimId})`);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.findOne({
|
||||
where: {name, claimId},
|
||||
})
|
||||
.then(result => {
|
||||
if (!result) {
|
||||
return resolve(null);
|
||||
};
|
||||
resolve(claimId);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
logger.error(error);
|
||||
reject(NO_CHANNEL);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Certificate.getLongChannelId = function (channelName, channelClaimId) {
|
||||
logger.debug(`getLongChannelId(${channelName}, ${channelClaimId})`);
|
||||
if (channelClaimId && (channelClaimId.length === 40)) { // if a full channel id is provided
|
||||
if (isLongChannelId(channelClaimId)) {
|
||||
return this.validateLongChannelId(channelName, channelClaimId);
|
||||
} else if (channelClaimId && channelClaimId.length < 40) { // if a short channel id is provided
|
||||
} else if (isShortChannelId(channelClaimId)) {
|
||||
return this.getLongChannelIdFromShortChannelId(channelName, channelClaimId);
|
||||
} else {
|
||||
return this.getLongChannelIdFromChannelName(channelName); // if no channel id provided
|
||||
return this.getLongChannelIdFromChannelName(channelName);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
const logger = require('winston');
|
||||
const { returnShortId } = require('../helpers/sequelizeHelpers.js');
|
||||
const returnShortId = require('./utils/returnShortId.js');
|
||||
const { assetDefaults: { thumbnail: defaultThumbnail }, details: { host } } = require('../../config/siteConfig.js');
|
||||
|
||||
const NO_CLAIM = 'NO_CLAIM';
|
||||
|
||||
function determineFileExtensionFromContentType (contentType) {
|
||||
switch (contentType) {
|
||||
case 'image/jpeg':
|
||||
|
@ -17,14 +19,14 @@ function determineFileExtensionFromContentType (contentType) {
|
|||
logger.debug('setting unknown file type as file extension jpeg');
|
||||
return 'jpeg';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function determineThumbnail (storedThumbnail, defaultThumbnail) {
|
||||
if (storedThumbnail === '') {
|
||||
return defaultThumbnail;
|
||||
}
|
||||
return storedThumbnail;
|
||||
};
|
||||
}
|
||||
|
||||
function prepareClaimData (claim) {
|
||||
// logger.debug('preparing claim data based on resolved data:', claim);
|
||||
|
@ -32,7 +34,15 @@ function prepareClaimData (claim) {
|
|||
claim['fileExt'] = determineFileExtensionFromContentType(claim.contentType);
|
||||
claim['host'] = host;
|
||||
return claim;
|
||||
};
|
||||
}
|
||||
|
||||
function isLongClaimId (claimId) {
|
||||
return (claimId && (claimId.length === 40));
|
||||
}
|
||||
|
||||
function isShortClaimId (claimId) {
|
||||
return (claimId && (claimId.length < 40));
|
||||
}
|
||||
|
||||
module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
||||
const Claim = sequelize.define(
|
||||
|
@ -265,6 +275,27 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
|||
});
|
||||
};
|
||||
|
||||
Claim.validateLongClaimId = function (name, claimId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.findOne({
|
||||
where: {
|
||||
name,
|
||||
claimId,
|
||||
},
|
||||
})
|
||||
.then(result => {
|
||||
if (!result) {
|
||||
return reject(NO_CLAIM);
|
||||
}
|
||||
resolve(claimId);
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error(error);
|
||||
reject(NO_CLAIM);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Claim.getLongClaimIdFromShortClaimId = function (name, shortId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this
|
||||
|
@ -279,13 +310,14 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
|||
.then(result => {
|
||||
switch (result.length) {
|
||||
case 0:
|
||||
return resolve(null);
|
||||
default: // note results must be sorted
|
||||
return reject(NO_CLAIM);
|
||||
default:
|
||||
return resolve(result[0].claimId);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
logger.error(error);
|
||||
reject(NO_CLAIM);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -295,48 +327,31 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
|||
this
|
||||
.findAll({
|
||||
where: { name },
|
||||
order: [['effectiveAmount', 'DESC'], ['height', 'ASC']], // note: maybe height and effective amount need to switch?
|
||||
order: [['effectiveAmount', 'DESC'], ['height', 'ASC']],
|
||||
})
|
||||
.then(result => {
|
||||
logger.debug('length of result', result.length);
|
||||
switch (result.length) {
|
||||
case 0:
|
||||
return resolve(null);
|
||||
return reject(NO_CLAIM);
|
||||
default:
|
||||
return resolve(result[0].dataValues.claimId);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Claim.validateLongClaimId = function (name, claimId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.findOne({
|
||||
where: {name, claimId},
|
||||
})
|
||||
.then(result => {
|
||||
if (!result) {
|
||||
return resolve(null);
|
||||
};
|
||||
resolve(claimId);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
logger.error(error);
|
||||
reject(NO_CLAIM);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Claim.getLongClaimId = function (claimName, claimId) {
|
||||
logger.debug(`getLongClaimId(${claimName}, ${claimId})`);
|
||||
if (claimId && (claimId.length === 40)) { // if a full claim id is provided
|
||||
// logger.debug(`getLongClaimId(${claimName}, ${claimId})`);
|
||||
if (isLongClaimId(claimId)) {
|
||||
return this.validateLongClaimId(claimName, claimId);
|
||||
} else if (claimId && claimId.length < 40) {
|
||||
return this.getLongClaimIdFromShortClaimId(claimName, claimId); // if a short claim id is provided
|
||||
} else if (isShortClaimId(claimId)) {
|
||||
return this.getLongClaimIdFromShortClaimId(claimName, claimId);
|
||||
} else {
|
||||
return this.getTopFreeClaimIdByClaimName(claimName); // if no claim id is provided
|
||||
return this.getTopFreeClaimIdByClaimName(claimName);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ const Claim = require('./claim.js');
|
|||
const File = require('./file.js');
|
||||
const Request = require('./request.js');
|
||||
const User = require('./user.js');
|
||||
const Blocked = require('./blocked.js');
|
||||
|
||||
const Sequelize = require('sequelize');
|
||||
const logger = require('winston');
|
||||
|
@ -42,6 +43,7 @@ db['Claim'] = sequelize.import('Claim', Claim);
|
|||
db['File'] = sequelize.import('File', File);
|
||||
db['Request'] = sequelize.import('Request', Request);
|
||||
db['User'] = sequelize.import('User', User);
|
||||
db['Blocked'] = sequelize.import('Blocked', Blocked);
|
||||
|
||||
// run model.association for each model in the db object that has an association
|
||||
logger.info('associating db models...');
|
||||
|
|
25
server/models/utils/returnShortId.js
Normal file
25
server/models/utils/returnShortId.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
const returnShortId = (claimsArray, longId) => {
|
||||
let claimIndex;
|
||||
let shortId = longId.substring(0, 1); // default short id is the first letter
|
||||
let shortIdLength = 0;
|
||||
// find the index of this claim id
|
||||
claimIndex = claimsArray.findIndex(element => {
|
||||
return element.claimId === longId;
|
||||
});
|
||||
if (claimIndex < 0) {
|
||||
throw new Error('claim id not found in claims list');
|
||||
}
|
||||
// get an array of all claims with lower height
|
||||
let possibleMatches = claimsArray.slice(0, claimIndex);
|
||||
// remove certificates with the same prefixes until none are left.
|
||||
while (possibleMatches.length > 0) {
|
||||
shortIdLength += 1;
|
||||
shortId = longId.substring(0, shortIdLength);
|
||||
possibleMatches = possibleMatches.filter(element => {
|
||||
return (element.claimId && (element.claimId.substring(0, shortIdLength) === shortId));
|
||||
});
|
||||
}
|
||||
return shortId;
|
||||
};
|
||||
|
||||
module.exports = returnShortId;
|
|
@ -1,33 +0,0 @@
|
|||
const { getClaimId } = require('../../controllers/serveController.js');
|
||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
||||
|
||||
const NO_CHANNEL = 'NO_CHANNEL';
|
||||
const NO_CLAIM = 'NO_CLAIM';
|
||||
|
||||
/*
|
||||
|
||||
route to get a long claim id
|
||||
|
||||
*/
|
||||
|
||||
const claimLongId = ({ ip, originalUrl, body, params }, res) => {
|
||||
const channelName = body.channelName;
|
||||
const channelClaimId = body.channelClaimId;
|
||||
const claimName = body.claimName;
|
||||
const claimId = body.claimId;
|
||||
getClaimId(channelName, channelClaimId, claimName, claimId)
|
||||
.then(result => {
|
||||
if (result === NO_CHANNEL) {
|
||||
return res.status(404).json({success: false, message: 'No matching channel could be found'});
|
||||
}
|
||||
if (result === NO_CLAIM) {
|
||||
return res.status(404).json({success: false, message: 'No matching claim id could be found'});
|
||||
}
|
||||
res.status(200).json({success: true, data: result});
|
||||
})
|
||||
.catch(error => {
|
||||
handleErrorResponse(originalUrl, ip, error, res);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = claimLongId;
|
|
@ -1,18 +1,19 @@
|
|||
const channelAvailability = require('./channelAvailability');
|
||||
const channelClaims = require('./channelClaims');
|
||||
const channelData = require('./channelData');
|
||||
const channelShortId = require('./channelShortId');
|
||||
const claimAvailability = require('./claimAvailability');
|
||||
const claimData = require('./claimData');
|
||||
const claimGet = require('./claimGet');
|
||||
const claimLongId = require('./claimLongId');
|
||||
const claimPublish = require('./claimPublish');
|
||||
const claimResolve = require('./claimResolve');
|
||||
const claimShortId = require('./claimShortId');
|
||||
const claimList = require('./claimList');
|
||||
const fileAvailability = require('./fileAvailability');
|
||||
const channelAvailability = require('../../controllers/api/channel/availability');
|
||||
const channelClaims = require('../../controllers/api/channel/claims');
|
||||
const channelData = require('../../controllers/api/channel/data');
|
||||
const channelShortId = require('../../controllers/api/channel/shortId');
|
||||
const claimAvailability = require('../../controllers/api/claim/availability');
|
||||
const claimBlockedList = require('../../controllers/api/claim/blockedList');
|
||||
const claimData = require('../../controllers/api/claim/data/');
|
||||
const claimGet = require('../../controllers/api/claim/get');
|
||||
const claimList = require('../../controllers/api/claim/list');
|
||||
const claimLongId = require('../../controllers/api/claim/longId');
|
||||
const claimPublish = require('../../controllers/api/claim/publish');
|
||||
const claimResolve = require('../../controllers/api/claim/resolve');
|
||||
const claimShortId = require('../../controllers/api/claim/shortId');
|
||||
const fileAvailability = require('../../controllers/api/file/availability');
|
||||
|
||||
const multipartMiddleware = require('../../helpers/multipartMiddleware');
|
||||
const multipartMiddleware = require('../utils/multipartMiddleware');
|
||||
|
||||
module.exports = (app) => {
|
||||
// channel routes
|
||||
|
@ -21,14 +22,15 @@ module.exports = (app) => {
|
|||
app.get('/api/channel/data/:channelName/:channelClaimId', channelData);
|
||||
app.get('/api/channel/claims/:channelName/:channelClaimId/:page', channelClaims);
|
||||
// claim routes
|
||||
app.get('/api/claim/list/:name', claimList);
|
||||
app.get('/api/claim/get/:name/:claimId', claimGet);
|
||||
app.get('/api/claim/availability/:name', claimAvailability);
|
||||
app.get('/api/claim/resolve/:name/:claimId', claimResolve);
|
||||
app.post('/api/claim/publish', multipartMiddleware, claimPublish);
|
||||
app.get('/api/claim/short-id/:longId/:name', claimShortId);
|
||||
app.post('/api/claim/long-id', claimLongId);
|
||||
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);
|
||||
app.post('/api/claim/publish', multipartMiddleware, claimPublish);
|
||||
app.get('/api/claim/resolve/:name/:claimId', claimResolve);
|
||||
app.get('/api/claim/short-id/:longId/:name', claimShortId);
|
||||
// file routes
|
||||
app.get('/api/file/availability/:name/:claimId', fileAvailability);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const serveAssetByClaim = require('./serveAssetByClaim');
|
||||
const serveAssetByIdentifierAndClaim = require('./serveAssetByIdentifierAndClaim');
|
||||
const serveAssetByClaim = require('../../controllers/assets/serveByClaim');
|
||||
const serveAssetByIdentifierAndClaim = require('../../controllers/assets/serveByIdentifierAndClaim');
|
||||
|
||||
module.exports = (app, db) => {
|
||||
app.get('/:identifier/:claim', serveAssetByIdentifierAndClaim);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
const speechPassport = require('../../speechPassport');
|
||||
const handleSignupRequest = require('./signup');
|
||||
const handleLoginRequest = require('./login');
|
||||
const handleLogoutRequest = require('./logout');
|
||||
const handleUserRequest = require('./user');
|
||||
const handleSignupRequest = require('../../controllers/auth/signup');
|
||||
const handleLoginRequest = require('../../controllers/auth/login');
|
||||
const handleLogoutRequest = require('../../controllers/auth/logout');
|
||||
const handleUserRequest = require('../../controllers/auth/user');
|
||||
|
||||
module.exports = (app) => {
|
||||
app.post('/signup', speechPassport.authenticate('local-signup'), handleSignupRequest);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const handlePageRequest = require('./sendReactApp');
|
||||
const handlePageRequest = require('../../controllers/pages/sendReactApp');
|
||||
|
||||
module.exports = (app) => {
|
||||
app.get('*', handlePageRequest);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const handlePageRequest = require('./sendReactApp');
|
||||
const handleEmbedRequest = require('./sendEmbedPage');
|
||||
const redirect = require('./redirect');
|
||||
const handlePageRequest = require('../../controllers/pages/sendReactApp');
|
||||
const handleEmbedRequest = require('../../controllers/pages/sendEmbedPage');
|
||||
const redirect = require('../../controllers/utils/redirect');
|
||||
|
||||
module.exports = (app) => {
|
||||
app.get('/', handlePageRequest);
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
const handlePageRender = require('../../render/build/handlePageRender.js');
|
||||
|
||||
const sendReactApp = (req, res) => {
|
||||
handlePageRender(req, res);
|
||||
};
|
||||
|
||||
module.exports = sendReactApp;
|
|
@ -1,5 +1,5 @@
|
|||
const multipart = require('connect-multiparty');
|
||||
const { publishing: { uploadDirectory } } = require('../../config/siteConfig.js');
|
||||
const { publishing: { uploadDirectory } } = require('../../../config/siteConfig.js');
|
||||
const multipartMiddleware = multipart({uploadDir: uploadDirectory});
|
||||
|
||||
module.exports = multipartMiddleware;
|
|
@ -1,10 +1,11 @@
|
|||
const passport = require('passport');
|
||||
const localLoginStrategy = require('./local-login.js');
|
||||
const localSignupStrategy = require('./local-signup.js');
|
||||
const { serializeSpeechUser, deserializeSpeechUser } = require('../helpers/authHelpers.js');
|
||||
const localLoginStrategy = require('./utils/local-login.js');
|
||||
const localSignupStrategy = require('./utils/local-signup.js');
|
||||
const serializeUser = require('./utils/serializeUser.js');
|
||||
const deserializeUser = require('./utils/deserializeUser.js');
|
||||
|
||||
passport.deserializeUser(deserializeSpeechUser);
|
||||
passport.serializeUser(serializeSpeechUser);
|
||||
passport.deserializeUser(deserializeUser);
|
||||
passport.serializeUser(serializeUser);
|
||||
passport.use('local-login', localLoginStrategy);
|
||||
passport.use('local-signup', localSignupStrategy);
|
||||
|
||||
|
|
7
server/speechPassport/utils/deserializeUser.js
Normal file
7
server/speechPassport/utils/deserializeUser.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
const deserializeUser = (user, done) => {
|
||||
// deserializes session and populates additional info to req.user
|
||||
console.log('deserializing user');
|
||||
done(null, user);
|
||||
};
|
||||
|
||||
module.exports = deserializeUser;
|
|
@ -1,6 +1,6 @@
|
|||
const PassportLocalStrategy = require('passport-local').Strategy;
|
||||
const logger = require('winston');
|
||||
const db = require('../models');
|
||||
const db = require('../../models');
|
||||
|
||||
const returnUserAndChannelInfo = (userInstance) => {
|
||||
return new Promise((resolve, reject) => {
|
|
@ -1,7 +1,7 @@
|
|||
const PassportLocalStrategy = require('passport-local').Strategy;
|
||||
const lbryApi = require('../helpers/lbryApi.js');
|
||||
const { createChannel } = require('../../lbrynet');
|
||||
const logger = require('winston');
|
||||
const db = require('../models');
|
||||
const db = require('../../models');
|
||||
|
||||
module.exports = new PassportLocalStrategy(
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ module.exports = new PassportLocalStrategy(
|
|||
// server-side validaton of inputs (username, password)
|
||||
|
||||
// create the channel and retrieve the metadata
|
||||
return lbryApi.createChannel(`@${username}`)
|
||||
return createChannel(`@${username}`)
|
||||
.then(tx => {
|
||||
// create user record
|
||||
const userData = {
|
7
server/speechPassport/utils/serializeUser.js
Normal file
7
server/speechPassport/utils/serializeUser.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
const serializeUser = (user, done) => {
|
||||
// returns user data to be serialized into session
|
||||
console.log('serializing user');
|
||||
done(null, user);
|
||||
};
|
||||
|
||||
module.exports = serializeUser;
|
|
@ -1,27 +1,34 @@
|
|||
const chai = require('chai');
|
||||
const expect = chai.expect;
|
||||
|
||||
describe('publishHelpers.js', function () {
|
||||
const publishHelpers = require('../../server/helpers/publishHelpers.js');
|
||||
describe('publish utils', function () {
|
||||
|
||||
describe('#parsePublishApiRequestBody()', function () {
|
||||
const parsePublishApiRequestBody = require('../../../server/controllers/api/claim/publish/parsePublishApiRequestBody.js');
|
||||
|
||||
it('should throw an error if no body', function () {
|
||||
expect(publishHelpers.parsePublishApiRequestBody.bind(this, null)).to.throw();
|
||||
expect(parsePublishApiRequestBody.bind(this, null)).to.throw();
|
||||
});
|
||||
|
||||
it('should throw an error if no body.name', function () {
|
||||
const bodyNoName = {};
|
||||
expect(publishHelpers.parsePublishApiRequestBody.bind(this, bodyNoName)).to.throw();
|
||||
expect(parsePublishApiRequestBody.bind(this, bodyNoName)).to.throw();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#parsePublishApiRequestFiles()', function () {
|
||||
const parsePublishApiRequestFiles = require('../../../server/controllers/api/claim/publish/parsePublishApiRequestFiles.js');
|
||||
|
||||
it('should throw an error if no files', function () {
|
||||
expect(publishHelpers.parsePublishApiRequestFiles.bind(this, null)).to.throw();
|
||||
expect(parsePublishApiRequestFiles.bind(this, null)).to.throw();
|
||||
});
|
||||
|
||||
it('should throw an error if no files.file', function () {
|
||||
const filesNoFile = {};
|
||||
expect(publishHelpers.parsePublishApiRequestFiles.bind(this, filesNoFile)).to.throw();
|
||||
expect(parsePublishApiRequestFiles.bind(this, filesNoFile)).to.throw();
|
||||
});
|
||||
|
||||
it('should throw an error if file.size is too large', function () {
|
||||
const filesTooBig = {
|
||||
file: {
|
||||
|
@ -31,8 +38,9 @@ describe('publishHelpers.js', function () {
|
|||
size: 10000001,
|
||||
},
|
||||
};
|
||||
expect(publishHelpers.parsePublishApiRequestFiles.bind(this, filesTooBig)).to.throw();
|
||||
expect(parsePublishApiRequestFiles.bind(this, filesTooBig)).to.throw();
|
||||
});
|
||||
|
||||
it('should throw error if not an accepted file type', function () {
|
||||
const filesWrongType = {
|
||||
file: {
|
||||
|
@ -42,8 +50,9 @@ describe('publishHelpers.js', function () {
|
|||
size: 10000000,
|
||||
},
|
||||
};
|
||||
expect(publishHelpers.parsePublishApiRequestFiles.bind(this, filesWrongType)).to.throw();
|
||||
expect(parsePublishApiRequestFiles.bind(this, filesWrongType)).to.throw();
|
||||
});
|
||||
|
||||
it('should throw NO error if no problems', function () {
|
||||
const filesNoProblems = {
|
||||
file: {
|
||||
|
@ -53,7 +62,7 @@ describe('publishHelpers.js', function () {
|
|||
size: 10000000,
|
||||
},
|
||||
};
|
||||
expect(publishHelpers.parsePublishApiRequestFiles.bind(this, filesNoProblems)).to.not.throw();
|
||||
expect(parsePublishApiRequestFiles.bind(this, filesNoProblems)).to.not.throw();
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in a new issue