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);
|
app.use(requestLogger);
|
||||||
|
|
||||||
// configure passport
|
// configure passport
|
||||||
const speechPassport = require('./server/speechPassport/index');
|
const speechPassport = require('./server/speechPassport');
|
||||||
// initialize passport
|
// initialize passport
|
||||||
const sessionKey = siteConfig.auth.sessionKey;
|
const sessionKey = siteConfig.auth.sessionKey;
|
||||||
app.use(cookieSession({
|
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 checkChannelAvailability = require('./checkChannelAvailability.js');
|
||||||
const { sendGATimingEvent } = require('../../helpers/googleAnalytics.js');
|
const { sendGATimingEvent } = require('../../../../utils/googleAnalytics.js');
|
||||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -4,7 +4,7 @@ module.exports = {
|
||||||
returnPaginatedChannelClaims (channelName, longChannelClaimId, claims, page) {
|
returnPaginatedChannelClaims (channelName, longChannelClaimId, claims, page) {
|
||||||
const totalPages = module.exports.determineTotalPages(claims);
|
const totalPages = module.exports.determineTotalPages(claims);
|
||||||
const paginationPage = module.exports.getPageFromQuery(page);
|
const paginationPage = module.exports.getPageFromQuery(page);
|
||||||
const viewData = {
|
return {
|
||||||
channelName : channelName,
|
channelName : channelName,
|
||||||
longChannelClaimId: longChannelClaimId,
|
longChannelClaimId: longChannelClaimId,
|
||||||
claims : module.exports.extractPageFromClaims(claims, paginationPage),
|
claims : module.exports.extractPageFromClaims(claims, paginationPage),
|
||||||
|
@ -14,7 +14,6 @@ module.exports = {
|
||||||
totalPages : totalPages,
|
totalPages : totalPages,
|
||||||
totalResults : module.exports.determineTotalClaims(claims),
|
totalResults : module.exports.determineTotalClaims(claims),
|
||||||
};
|
};
|
||||||
return viewData;
|
|
||||||
},
|
},
|
||||||
getPageFromQuery (page) {
|
getPageFromQuery (page) {
|
||||||
if (page) {
|
if (page) {
|
||||||
|
@ -30,8 +29,7 @@ module.exports = {
|
||||||
// logger.debug(`pageNumber ${pageNumber} is number?`, Number.isInteger(pageNumber));
|
// logger.debug(`pageNumber ${pageNumber} is number?`, Number.isInteger(pageNumber));
|
||||||
const claimStartIndex = (pageNumber - 1) * CLAIMS_PER_PAGE;
|
const claimStartIndex = (pageNumber - 1) * CLAIMS_PER_PAGE;
|
||||||
const claimEndIndex = claimStartIndex + CLAIMS_PER_PAGE;
|
const claimEndIndex = claimStartIndex + CLAIMS_PER_PAGE;
|
||||||
const pageOfClaims = claims.slice(claimStartIndex, claimEndIndex);
|
return claims.slice(claimStartIndex, claimEndIndex);
|
||||||
return pageOfClaims;
|
|
||||||
},
|
},
|
||||||
determineTotalPages (claims) {
|
determineTotalPages (claims) {
|
||||||
if (!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('../../../utils/errorHandlers.js');
|
||||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
const getChannelClaims = require('./getChannelClaims.js');
|
||||||
|
|
||||||
const NO_CHANNEL = 'NO_CHANNEL';
|
const NO_CHANNEL = 'NO_CHANNEL';
|
||||||
|
|
||||||
|
@ -16,12 +16,15 @@ const channelClaims = ({ ip, originalUrl, body, params }, res) => {
|
||||||
const page = params.page;
|
const page = params.page;
|
||||||
getChannelClaims(channelName, channelClaimId, page)
|
getChannelClaims(channelName, channelClaimId, page)
|
||||||
.then(data => {
|
.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 => {
|
.catch(error => {
|
||||||
|
if (error === NO_CHANNEL) {
|
||||||
|
return res.status(404).json({
|
||||||
|
success: false,
|
||||||
|
message: 'No matching channel was found',
|
||||||
|
});
|
||||||
|
}
|
||||||
handleErrorResponse(originalUrl, ip, error, res);
|
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('../../../utils/errorHandlers.js');
|
||||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
|
||||||
|
const getChannelData = require('./getChannelData.js');
|
||||||
|
|
||||||
const NO_CHANNEL = 'NO_CHANNEL';
|
const NO_CHANNEL = 'NO_CHANNEL';
|
||||||
|
|
||||||
|
@ -13,14 +14,20 @@ const channelData = ({ ip, originalUrl, body, params }, res) => {
|
||||||
const channelName = params.channelName;
|
const channelName = params.channelName;
|
||||||
let channelClaimId = params.channelClaimId;
|
let channelClaimId = params.channelClaimId;
|
||||||
if (channelClaimId === 'none') channelClaimId = null;
|
if (channelClaimId === 'none') channelClaimId = null;
|
||||||
getChannelData(channelName, channelClaimId, 0)
|
getChannelData(channelName, channelClaimId)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data === NO_CHANNEL) {
|
res.status(200).json({
|
||||||
return res.status(404).json({success: false, message: 'No matching channel was found'});
|
success: true,
|
||||||
}
|
data
|
||||||
res.status(200).json({success: true, data});
|
});
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
if (error === NO_CHANNEL) {
|
||||||
|
return res.status(404).json({
|
||||||
|
success: false,
|
||||||
|
message: 'No matching channel was found',
|
||||||
|
});
|
||||||
|
}
|
||||||
handleErrorResponse(originalUrl, ip, error, res);
|
handleErrorResponse(originalUrl, ip, error, res);
|
||||||
});
|
});
|
||||||
};
|
};
|
|
@ -1,5 +1,5 @@
|
||||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||||
const db = require('../../models');
|
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 checkClaimAvailability = require('./checkClaimAvailability.js');
|
||||||
const { sendGATimingEvent } = require('../../helpers/googleAnalytics.js');
|
const { sendGATimingEvent } = require('../../../../utils/googleAnalytics.js');
|
||||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.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 claimAvailability = ({ ip, originalUrl, params: { name } }, res) => {
|
||||||
const gaStartTime = Date.now();
|
const gaStartTime = Date.now();
|
||||||
claimNameIsAvailable(name)
|
checkClaimAvailability(name)
|
||||||
.then(result => {
|
.then(result => {
|
||||||
res.status(200).json(result);
|
res.status(200).json(result);
|
||||||
sendGATimingEvent('end-to-end', 'claim name availability', name, gaStartTime, Date.now());
|
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 { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||||
const db = require('../../models');
|
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 { getClaim } = require('../../../../lbrynet');
|
||||||
const { addGetResultsToFileData, createFileData } = require('../../helpers/publishHelpers.js');
|
const addGetResultsToFileData = require('./addGetResultsToFileData.js');
|
||||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
const createFileData = require('./createFileData.js');
|
||||||
const db = require('../../models');
|
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||||
|
const db = require('../../../../models');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const { getClaimList } = require('../../helpers/lbryApi.js');
|
const { getClaimList } = require('../../../../lbrynet');
|
||||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
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 { details: { host } } = require('../../../../../config/siteConfig.js');
|
||||||
const { claimNameIsAvailable, publish } = require('../../controllers/publishController.js');
|
|
||||||
const { authenticateUser } = require('../../auth/authentication.js');
|
const { sendGATimingEvent } = require('../../../../utils/googleAnalytics.js');
|
||||||
const { sendGATimingEvent } = require('../../helpers/googleAnalytics.js');
|
|
||||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||||
const { details: { host } } = require('../../../config/siteConfig.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
|
Promise
|
||||||
.all([
|
.all([
|
||||||
authenticateUser(channelName, channelId, channelPassword, user),
|
authenticateUser(channelName, channelId, channelPassword, user),
|
||||||
claimNameIsAvailable(name),
|
checkClaimAvailability(name),
|
||||||
createBasicPublishParams(filePath, name, title, description, license, nsfw, thumbnail),
|
createBasicPublishParams(filePath, name, title, description, license, nsfw, thumbnail),
|
||||||
createThumbnailPublishParams(thumbnailFilePath, name, license, nsfw),
|
createThumbnailPublishParams(thumbnailFilePath, name, license, nsfw),
|
||||||
])
|
])
|
||||||
|
@ -39,7 +47,7 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user }, res) => {
|
||||||
publishParams['channel_name'] = channelName;
|
publishParams['channel_name'] = channelName;
|
||||||
publishParams['channel_id'] = channelClaimId;
|
publishParams['channel_id'] = channelClaimId;
|
||||||
}
|
}
|
||||||
// publish the thumbnail
|
// publish the thumbnail, if one exists
|
||||||
if (thumbnailPublishParams) {
|
if (thumbnailPublishParams) {
|
||||||
publish(thumbnailPublishParams, thumbnailFileName, thumbnailFileType);
|
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 { resolveUri } = require('../../../../lbrynet/index');
|
||||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||||
const db = require('../../models');
|
const db = require('../../../../models');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const { handleErrorResponse } = require('../../helpers/errorHandlers.js');
|
const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
|
||||||
const db = require('../../models');
|
const db = require('../../../../models');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
const { sendGAServeEvent } = require('../../helpers/googleAnalytics');
|
const { sendGAServeEvent } = require('../../../utils/googleAnalytics');
|
||||||
const { determineResponseType, logRequestData, getClaimIdAndServeAsset } = require('../../helpers/serveHelpers.js');
|
const handleShowRender = require('../../../render/build/handleShowRender.js');
|
||||||
const lbryUri = require('../../helpers/lbryUri.js');
|
|
||||||
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';
|
const SERVE = 'SERVE';
|
||||||
|
|
||||||
/*
|
/*
|
|
@ -1,12 +1,12 @@
|
||||||
const { sendGAServeEvent } = require('../../helpers/googleAnalytics');
|
const { sendGAServeEvent } = require('../../../utils/googleAnalytics');
|
||||||
const {
|
const handleShowRender = require('../../../render/build/handleShowRender.js');
|
||||||
determineResponseType,
|
|
||||||
flipClaimNameAndIdForBackwardsCompatibility,
|
const lbryUri = require('../utils/lbryUri.js');
|
||||||
logRequestData,
|
|
||||||
getClaimIdAndServeAsset,
|
const determineResponseType = require('../utils/determineResponseType.js');
|
||||||
} = require('../../helpers/serveHelpers.js');
|
const getClaimIdAndServeAsset = require('../utils/getClaimIdAndServeAsset.js');
|
||||||
const lbryUri = require('../../helpers/lbryUri.js');
|
const flipClaimNameAndId = require('../utils/flipClaimNameAndId.js');
|
||||||
const handleShowRender = require('../../render/build/handleShowRender.js');
|
const logRequestData = require('../utils/logRequestData.js');
|
||||||
|
|
||||||
const SERVE = 'SERVE';
|
const SERVE = 'SERVE';
|
||||||
|
|
||||||
|
@ -46,8 +46,9 @@ const serverAssetByIdentifierAndClaim = (req, res) => {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(400).json({success: false, message: error.message});
|
return res.status(400).json({success: false, message: error.message});
|
||||||
}
|
}
|
||||||
|
// for backwards compatability, flip claim name and claim id if necessary
|
||||||
if (!isChannel) {
|
if (!isChannel) {
|
||||||
[claimId, claimName] = flipClaimNameAndIdForBackwardsCompatibility(claimId, claimName);
|
[claimId, claimName] = flipClaimNameAndId(claimId, claimName);
|
||||||
}
|
}
|
||||||
// log the request data for debugging
|
// log the request data for debugging
|
||||||
logRequestData(responseType, claimName, channelName, claimId);
|
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) => {
|
const login = (req, res, next) => {
|
||||||
speechPassport.authenticate('local-login', (err, user, info) => {
|
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;
|
message = error.message;
|
||||||
} else {
|
} else {
|
||||||
message = error;
|
message = error;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
return [status, message];
|
return [status, message];
|
||||||
},
|
},
|
||||||
useObjectPropertiesIfNoKeys: function (err) {
|
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 axios = require('axios');
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const { api: { apiHost, apiPort } } = require('../../config/lbryConfig.js');
|
const { api: { apiHost, apiPort } } = require('../../config/lbryConfig.js');
|
||||||
const lbryApiUri = 'http://' + apiHost + ':' + apiPort;
|
const lbrynetUri = 'http://' + apiHost + ':' + apiPort;
|
||||||
const { chooseGaLbrynetPublishLabel, sendGATimingEvent } = require('./googleAnalytics.js');
|
const { chooseGaLbrynetPublishLabel, sendGATimingEvent } = require('../utils/googleAnalytics.js');
|
||||||
|
const handleLbrynetResponse = require('./utils/handleLbrynetResponse.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));
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
publishClaim (publishParams) {
|
publishClaim (publishParams) {
|
||||||
|
@ -26,7 +11,7 @@ module.exports = {
|
||||||
const gaStartTime = Date.now();
|
const gaStartTime = Date.now();
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
axios
|
axios
|
||||||
.post(lbryApiUri, {
|
.post(lbrynetUri, {
|
||||||
method: 'publish',
|
method: 'publish',
|
||||||
params: publishParams,
|
params: publishParams,
|
||||||
})
|
})
|
||||||
|
@ -44,7 +29,7 @@ module.exports = {
|
||||||
const gaStartTime = Date.now();
|
const gaStartTime = Date.now();
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
axios
|
axios
|
||||||
.post(lbryApiUri, {
|
.post(lbrynetUri, {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { uri, timeout: 20 },
|
params: { uri, timeout: 20 },
|
||||||
})
|
})
|
||||||
|
@ -62,7 +47,7 @@ module.exports = {
|
||||||
const gaStartTime = Date.now();
|
const gaStartTime = Date.now();
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
axios
|
axios
|
||||||
.post(lbryApiUri, {
|
.post(lbrynetUri, {
|
||||||
method: 'claim_list',
|
method: 'claim_list',
|
||||||
params: { name: claimName },
|
params: { name: claimName },
|
||||||
})
|
})
|
||||||
|
@ -80,7 +65,7 @@ module.exports = {
|
||||||
const gaStartTime = Date.now();
|
const gaStartTime = Date.now();
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
axios
|
axios
|
||||||
.post(lbryApiUri, {
|
.post(lbrynetUri, {
|
||||||
method: 'resolve',
|
method: 'resolve',
|
||||||
params: { uri },
|
params: { uri },
|
||||||
})
|
})
|
||||||
|
@ -102,7 +87,7 @@ module.exports = {
|
||||||
const gaStartTime = Date.now();
|
const gaStartTime = Date.now();
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
axios
|
axios
|
||||||
.post(lbryApiUri, {
|
.post(lbrynetUri, {
|
||||||
method: 'settings_get',
|
method: 'settings_get',
|
||||||
})
|
})
|
||||||
.then(({ data }) => {
|
.then(({ data }) => {
|
||||||
|
@ -124,7 +109,7 @@ module.exports = {
|
||||||
const gaStartTime = Date.now();
|
const gaStartTime = Date.now();
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
axios
|
axios
|
||||||
.post(lbryApiUri, {
|
.post(lbrynetUri, {
|
||||||
method: 'channel_new',
|
method: 'channel_new',
|
||||||
params: {
|
params: {
|
||||||
channel_name: name,
|
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 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 }) => {
|
module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
||||||
const Certificate = sequelize.define(
|
const Certificate = sequelize.define(
|
||||||
|
@ -110,7 +120,7 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
||||||
.then(result => {
|
.then(result => {
|
||||||
switch (result.length) {
|
switch (result.length) {
|
||||||
case 0:
|
case 0:
|
||||||
throw new Error('No channel(s) found with that channel name');
|
return reject(NO_CHANNEL);
|
||||||
default:
|
default:
|
||||||
return resolve(returnShortId(result, longChannelId));
|
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) {
|
Certificate.getLongChannelIdFromShortChannelId = function (channelName, channelClaimId) {
|
||||||
logger.debug(`getLongChannelIdFromShortChannelId(${channelName}, ${channelClaimId})`);
|
logger.debug(`getLongChannelIdFromShortChannelId(${channelName}, ${channelClaimId})`);
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
@ -137,13 +166,14 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
||||||
.then(result => {
|
.then(result => {
|
||||||
switch (result.length) {
|
switch (result.length) {
|
||||||
case 0:
|
case 0:
|
||||||
return resolve(null);
|
return reject(NO_CHANNEL);
|
||||||
default: // note results must be sorted
|
default:
|
||||||
return resolve(result[0].claimId);
|
return resolve(result[0].claimId);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
reject(error);
|
logger.error(error);
|
||||||
|
reject(NO_CHANNEL);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -159,43 +189,26 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
||||||
.then(result => {
|
.then(result => {
|
||||||
switch (result.length) {
|
switch (result.length) {
|
||||||
case 0:
|
case 0:
|
||||||
return resolve(null);
|
return reject(NO_CHANNEL);
|
||||||
default:
|
default:
|
||||||
return resolve(result[0].claimId);
|
return resolve(result[0].claimId);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
reject(error);
|
logger.error(error);
|
||||||
});
|
reject(NO_CHANNEL);
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Certificate.getLongChannelId = function (channelName, channelClaimId) {
|
Certificate.getLongChannelId = function (channelName, channelClaimId) {
|
||||||
logger.debug(`getLongChannelId(${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);
|
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);
|
return this.getLongChannelIdFromShortChannelId(channelName, channelClaimId);
|
||||||
} else {
|
} else {
|
||||||
return this.getLongChannelIdFromChannelName(channelName); // if no channel id provided
|
return this.getLongChannelIdFromChannelName(channelName);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
const logger = require('winston');
|
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 { assetDefaults: { thumbnail: defaultThumbnail }, details: { host } } = require('../../config/siteConfig.js');
|
||||||
|
|
||||||
|
const NO_CLAIM = 'NO_CLAIM';
|
||||||
|
|
||||||
function determineFileExtensionFromContentType (contentType) {
|
function determineFileExtensionFromContentType (contentType) {
|
||||||
switch (contentType) {
|
switch (contentType) {
|
||||||
case 'image/jpeg':
|
case 'image/jpeg':
|
||||||
|
@ -17,14 +19,14 @@ function determineFileExtensionFromContentType (contentType) {
|
||||||
logger.debug('setting unknown file type as file extension jpeg');
|
logger.debug('setting unknown file type as file extension jpeg');
|
||||||
return 'jpeg';
|
return 'jpeg';
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function determineThumbnail (storedThumbnail, defaultThumbnail) {
|
function determineThumbnail (storedThumbnail, defaultThumbnail) {
|
||||||
if (storedThumbnail === '') {
|
if (storedThumbnail === '') {
|
||||||
return defaultThumbnail;
|
return defaultThumbnail;
|
||||||
}
|
}
|
||||||
return storedThumbnail;
|
return storedThumbnail;
|
||||||
};
|
}
|
||||||
|
|
||||||
function prepareClaimData (claim) {
|
function prepareClaimData (claim) {
|
||||||
// logger.debug('preparing claim data based on resolved data:', claim);
|
// logger.debug('preparing claim data based on resolved data:', claim);
|
||||||
|
@ -32,7 +34,15 @@ function prepareClaimData (claim) {
|
||||||
claim['fileExt'] = determineFileExtensionFromContentType(claim.contentType);
|
claim['fileExt'] = determineFileExtensionFromContentType(claim.contentType);
|
||||||
claim['host'] = host;
|
claim['host'] = host;
|
||||||
return claim;
|
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 }) => {
|
module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
||||||
const Claim = sequelize.define(
|
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) {
|
Claim.getLongClaimIdFromShortClaimId = function (name, shortId) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this
|
this
|
||||||
|
@ -279,13 +310,14 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
||||||
.then(result => {
|
.then(result => {
|
||||||
switch (result.length) {
|
switch (result.length) {
|
||||||
case 0:
|
case 0:
|
||||||
return resolve(null);
|
return reject(NO_CLAIM);
|
||||||
default: // note results must be sorted
|
default:
|
||||||
return resolve(result[0].claimId);
|
return resolve(result[0].claimId);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
reject(error);
|
logger.error(error);
|
||||||
|
reject(NO_CLAIM);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -295,48 +327,31 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
|
||||||
this
|
this
|
||||||
.findAll({
|
.findAll({
|
||||||
where: { name },
|
where: { name },
|
||||||
order: [['effectiveAmount', 'DESC'], ['height', 'ASC']], // note: maybe height and effective amount need to switch?
|
order: [['effectiveAmount', 'DESC'], ['height', 'ASC']],
|
||||||
})
|
})
|
||||||
.then(result => {
|
.then(result => {
|
||||||
logger.debug('length of result', result.length);
|
|
||||||
switch (result.length) {
|
switch (result.length) {
|
||||||
case 0:
|
case 0:
|
||||||
return resolve(null);
|
return reject(NO_CLAIM);
|
||||||
default:
|
default:
|
||||||
return resolve(result[0].dataValues.claimId);
|
return resolve(result[0].dataValues.claimId);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
reject(error);
|
logger.error(error);
|
||||||
});
|
reject(NO_CLAIM);
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Claim.getLongClaimId = function (claimName, claimId) {
|
Claim.getLongClaimId = function (claimName, claimId) {
|
||||||
logger.debug(`getLongClaimId(${claimName}, ${claimId})`);
|
// logger.debug(`getLongClaimId(${claimName}, ${claimId})`);
|
||||||
if (claimId && (claimId.length === 40)) { // if a full claim id is provided
|
if (isLongClaimId(claimId)) {
|
||||||
return this.validateLongClaimId(claimName, claimId);
|
return this.validateLongClaimId(claimName, claimId);
|
||||||
} else if (claimId && claimId.length < 40) {
|
} else if (isShortClaimId(claimId)) {
|
||||||
return this.getLongClaimIdFromShortClaimId(claimName, claimId); // if a short claim id is provided
|
return this.getLongClaimIdFromShortClaimId(claimName, claimId);
|
||||||
} else {
|
} 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 File = require('./file.js');
|
||||||
const Request = require('./request.js');
|
const Request = require('./request.js');
|
||||||
const User = require('./user.js');
|
const User = require('./user.js');
|
||||||
|
const Blocked = require('./blocked.js');
|
||||||
|
|
||||||
const Sequelize = require('sequelize');
|
const Sequelize = require('sequelize');
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
|
@ -42,6 +43,7 @@ db['Claim'] = sequelize.import('Claim', Claim);
|
||||||
db['File'] = sequelize.import('File', File);
|
db['File'] = sequelize.import('File', File);
|
||||||
db['Request'] = sequelize.import('Request', Request);
|
db['Request'] = sequelize.import('Request', Request);
|
||||||
db['User'] = sequelize.import('User', User);
|
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
|
// run model.association for each model in the db object that has an association
|
||||||
logger.info('associating db models...');
|
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 channelAvailability = require('../../controllers/api/channel/availability');
|
||||||
const channelClaims = require('./channelClaims');
|
const channelClaims = require('../../controllers/api/channel/claims');
|
||||||
const channelData = require('./channelData');
|
const channelData = require('../../controllers/api/channel/data');
|
||||||
const channelShortId = require('./channelShortId');
|
const channelShortId = require('../../controllers/api/channel/shortId');
|
||||||
const claimAvailability = require('./claimAvailability');
|
const claimAvailability = require('../../controllers/api/claim/availability');
|
||||||
const claimData = require('./claimData');
|
const claimBlockedList = require('../../controllers/api/claim/blockedList');
|
||||||
const claimGet = require('./claimGet');
|
const claimData = require('../../controllers/api/claim/data/');
|
||||||
const claimLongId = require('./claimLongId');
|
const claimGet = require('../../controllers/api/claim/get');
|
||||||
const claimPublish = require('./claimPublish');
|
const claimList = require('../../controllers/api/claim/list');
|
||||||
const claimResolve = require('./claimResolve');
|
const claimLongId = require('../../controllers/api/claim/longId');
|
||||||
const claimShortId = require('./claimShortId');
|
const claimPublish = require('../../controllers/api/claim/publish');
|
||||||
const claimList = require('./claimList');
|
const claimResolve = require('../../controllers/api/claim/resolve');
|
||||||
const fileAvailability = require('./fileAvailability');
|
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) => {
|
module.exports = (app) => {
|
||||||
// channel routes
|
// channel routes
|
||||||
|
@ -21,14 +22,15 @@ module.exports = (app) => {
|
||||||
app.get('/api/channel/data/:channelName/:channelClaimId', channelData);
|
app.get('/api/channel/data/:channelName/:channelClaimId', channelData);
|
||||||
app.get('/api/channel/claims/:channelName/:channelClaimId/:page', channelClaims);
|
app.get('/api/channel/claims/:channelName/:channelClaimId/:page', channelClaims);
|
||||||
// claim routes
|
// 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/availability/:name', claimAvailability);
|
||||||
app.get('/api/claim/resolve/:name/:claimId', claimResolve);
|
app.get('/api/claim/blocked-list/', claimBlockedList);
|
||||||
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/data/:claimName/:claimId', claimData);
|
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
|
// file routes
|
||||||
app.get('/api/file/availability/:name/:claimId', fileAvailability);
|
app.get('/api/file/availability/:name/:claimId', fileAvailability);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const serveAssetByClaim = require('./serveAssetByClaim');
|
const serveAssetByClaim = require('../../controllers/assets/serveByClaim');
|
||||||
const serveAssetByIdentifierAndClaim = require('./serveAssetByIdentifierAndClaim');
|
const serveAssetByIdentifierAndClaim = require('../../controllers/assets/serveByIdentifierAndClaim');
|
||||||
|
|
||||||
module.exports = (app, db) => {
|
module.exports = (app, db) => {
|
||||||
app.get('/:identifier/:claim', serveAssetByIdentifierAndClaim);
|
app.get('/:identifier/:claim', serveAssetByIdentifierAndClaim);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
const speechPassport = require('../../speechPassport');
|
const speechPassport = require('../../speechPassport');
|
||||||
const handleSignupRequest = require('./signup');
|
const handleSignupRequest = require('../../controllers/auth/signup');
|
||||||
const handleLoginRequest = require('./login');
|
const handleLoginRequest = require('../../controllers/auth/login');
|
||||||
const handleLogoutRequest = require('./logout');
|
const handleLogoutRequest = require('../../controllers/auth/logout');
|
||||||
const handleUserRequest = require('./user');
|
const handleUserRequest = require('../../controllers/auth/user');
|
||||||
|
|
||||||
module.exports = (app) => {
|
module.exports = (app) => {
|
||||||
app.post('/signup', speechPassport.authenticate('local-signup'), handleSignupRequest);
|
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) => {
|
module.exports = (app) => {
|
||||||
app.get('*', handlePageRequest);
|
app.get('*', handlePageRequest);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
const handlePageRequest = require('./sendReactApp');
|
const handlePageRequest = require('../../controllers/pages/sendReactApp');
|
||||||
const handleEmbedRequest = require('./sendEmbedPage');
|
const handleEmbedRequest = require('../../controllers/pages/sendEmbedPage');
|
||||||
const redirect = require('./redirect');
|
const redirect = require('../../controllers/utils/redirect');
|
||||||
|
|
||||||
module.exports = (app) => {
|
module.exports = (app) => {
|
||||||
app.get('/', handlePageRequest);
|
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 multipart = require('connect-multiparty');
|
||||||
const { publishing: { uploadDirectory } } = require('../../config/siteConfig.js');
|
const { publishing: { uploadDirectory } } = require('../../../config/siteConfig.js');
|
||||||
const multipartMiddleware = multipart({uploadDir: uploadDirectory});
|
const multipartMiddleware = multipart({uploadDir: uploadDirectory});
|
||||||
|
|
||||||
module.exports = multipartMiddleware;
|
module.exports = multipartMiddleware;
|
|
@ -1,10 +1,11 @@
|
||||||
const passport = require('passport');
|
const passport = require('passport');
|
||||||
const localLoginStrategy = require('./local-login.js');
|
const localLoginStrategy = require('./utils/local-login.js');
|
||||||
const localSignupStrategy = require('./local-signup.js');
|
const localSignupStrategy = require('./utils/local-signup.js');
|
||||||
const { serializeSpeechUser, deserializeSpeechUser } = require('../helpers/authHelpers.js');
|
const serializeUser = require('./utils/serializeUser.js');
|
||||||
|
const deserializeUser = require('./utils/deserializeUser.js');
|
||||||
|
|
||||||
passport.deserializeUser(deserializeSpeechUser);
|
passport.deserializeUser(deserializeUser);
|
||||||
passport.serializeUser(serializeSpeechUser);
|
passport.serializeUser(serializeUser);
|
||||||
passport.use('local-login', localLoginStrategy);
|
passport.use('local-login', localLoginStrategy);
|
||||||
passport.use('local-signup', localSignupStrategy);
|
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 PassportLocalStrategy = require('passport-local').Strategy;
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const db = require('../models');
|
const db = require('../../models');
|
||||||
|
|
||||||
const returnUserAndChannelInfo = (userInstance) => {
|
const returnUserAndChannelInfo = (userInstance) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
|
@ -1,7 +1,7 @@
|
||||||
const PassportLocalStrategy = require('passport-local').Strategy;
|
const PassportLocalStrategy = require('passport-local').Strategy;
|
||||||
const lbryApi = require('../helpers/lbryApi.js');
|
const { createChannel } = require('../../lbrynet');
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const db = require('../models');
|
const db = require('../../models');
|
||||||
|
|
||||||
module.exports = new PassportLocalStrategy(
|
module.exports = new PassportLocalStrategy(
|
||||||
{
|
{
|
||||||
|
@ -14,7 +14,7 @@ module.exports = new PassportLocalStrategy(
|
||||||
// server-side validaton of inputs (username, password)
|
// server-side validaton of inputs (username, password)
|
||||||
|
|
||||||
// create the channel and retrieve the metadata
|
// create the channel and retrieve the metadata
|
||||||
return lbryApi.createChannel(`@${username}`)
|
return createChannel(`@${username}`)
|
||||||
.then(tx => {
|
.then(tx => {
|
||||||
// create user record
|
// create user record
|
||||||
const userData = {
|
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 chai = require('chai');
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
|
||||||
describe('publishHelpers.js', function () {
|
describe('publish utils', function () {
|
||||||
const publishHelpers = require('../../server/helpers/publishHelpers.js');
|
|
||||||
|
|
||||||
describe('#parsePublishApiRequestBody()', function () {
|
describe('#parsePublishApiRequestBody()', function () {
|
||||||
|
const parsePublishApiRequestBody = require('../../../server/controllers/api/claim/publish/parsePublishApiRequestBody.js');
|
||||||
|
|
||||||
it('should throw an error if no body', function () {
|
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 () {
|
it('should throw an error if no body.name', function () {
|
||||||
const bodyNoName = {};
|
const bodyNoName = {};
|
||||||
expect(publishHelpers.parsePublishApiRequestBody.bind(this, bodyNoName)).to.throw();
|
expect(parsePublishApiRequestBody.bind(this, bodyNoName)).to.throw();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#parsePublishApiRequestFiles()', function () {
|
describe('#parsePublishApiRequestFiles()', function () {
|
||||||
|
const parsePublishApiRequestFiles = require('../../../server/controllers/api/claim/publish/parsePublishApiRequestFiles.js');
|
||||||
|
|
||||||
it('should throw an error if no files', function () {
|
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 () {
|
it('should throw an error if no files.file', function () {
|
||||||
const filesNoFile = {};
|
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 () {
|
it('should throw an error if file.size is too large', function () {
|
||||||
const filesTooBig = {
|
const filesTooBig = {
|
||||||
file: {
|
file: {
|
||||||
|
@ -31,8 +38,9 @@ describe('publishHelpers.js', function () {
|
||||||
size: 10000001,
|
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 () {
|
it('should throw error if not an accepted file type', function () {
|
||||||
const filesWrongType = {
|
const filesWrongType = {
|
||||||
file: {
|
file: {
|
||||||
|
@ -42,8 +50,9 @@ describe('publishHelpers.js', function () {
|
||||||
size: 10000000,
|
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 () {
|
it('should throw NO error if no problems', function () {
|
||||||
const filesNoProblems = {
|
const filesNoProblems = {
|
||||||
file: {
|
file: {
|
||||||
|
@ -53,7 +62,7 @@ describe('publishHelpers.js', function () {
|
||||||
size: 10000000,
|
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