fixed the anonymous discrepency

This commit is contained in:
bill bittner 2017-11-03 13:37:23 -07:00
parent d92f499269
commit e34e78c169
8 changed files with 97 additions and 96 deletions

View file

@ -36,17 +36,17 @@ spee.ch is a single-serving site that reads and publishes images and videos to a
#### POST
* /api/publish
* example: `curl -X POST -F 'name=MyPictureName' -F 'nsfw=false' -F 'file=@/path/to/my/picture.jpeg' https://spee.ch/api/publish`
* example: `curl -X POST -F 'name=MyPictureName' -F 'file=@/path/to/myPicture.jpeg' https://spee.ch/api/publish`
* Parameters:
* name (string)
* nsfw (boolean)
* file (.mp4, .jpeg, .jpg, .gif, or .png)
* license (string, optional)
* title (string, optional)
* description (string, optional)
* thumbnail (string, optional) (for .mp4 uploads only)
* channelName(string, optional)
* channelPassword (string, optional)
* `name`
* `file` (.mp4, .jpeg, .jpg, .gif, or .png)
* `nsfw` (optional)
* `license` (optional)
* `title` (optional)
* `description` (optional)
* `thumbnail` url to thumbnail image, for .mp4 uploads only (optional)
* `channelName`(optional)
* `channelPassword` (optional,; required if `channelName` is provided)
## bugs
If you find a bug or experience a problem, please report your issue here on github and find us in the lbry slack!

View file

@ -2,12 +2,14 @@ const db = require('../models');
const logger = require('winston');
module.exports = {
authenticateChannelCredentials (channelName, userPassword) {
authenticateChannelCredentials (skipAuth, channelName, userPassword) {
return new Promise((resolve, reject) => {
if (!channelName) {
resolve(true);
// skip authentication if not needed
if (skipAuth) {
resolve(skipAuth);
return;
}
// authentication
const userName = channelName.substring(1);
logger.debug(`authenticateChannelCredentials > channelName: ${channelName} username: ${userName} pass: ${userPassword}`);
db.User
@ -18,17 +20,23 @@ module.exports = {
resolve(false);
return;
}
if (!user.validPassword(userPassword, user.password)) {
return user.comparePassword(userPassword, (passwordErr, isMatch) => {
if (passwordErr) {
logger.error('comparePassword error:', passwordErr);
resolve(false);
return;
}
if (!isMatch) {
logger.debug('incorrect password');
resolve(false);
return;
}
logger.debug('user found:', user.dataValues);
logger.debug('...password was a match...');
resolve(true);
});
})
.catch(error => {
logger.error(error);
reject();
reject(error);
});
});
},

View file

@ -13,17 +13,16 @@ module.exports = {
.then(tx => {
logger.info(`Successfully published ${fileName}`, tx);
publishResults = tx;
return db.Channel.findOne({where: {channelName: publishParams.channel_name}}); // note: should this be db.User ??
})
.then(channel => {
let certificateId;
if (channel) {
certificateId = channel.channelClaimId;
logger.debug('successfully found channel in Channel table');
if (publishParams.channel_name) {
logger.debug(`this claim was published in channel: ${publishParams.channel_name}`);
return db.Channel.findOne({where: {channelName: publishParams.channel_name}}).then(channel => { return channel.channelClaimId });
} else {
certificateId = null;
logger.debug('channel for publish not found in Channel table');
};
logger.debug('this claim was published in channel: n/a');
return null;
}
})
.then(certificateId => {
logger.debug(`certificateId: ${certificateId}`);
const fileRecord = {
name : publishParams.name,
claimId : publishResults.claim_id,

View file

@ -3,11 +3,12 @@ const { postToStats } = require('../controllers/statsController.js');
module.exports = {
returnErrorMessageAndStatus: function (error) {
let status;
let message;
let status, message;
// check for daemon being turned off
if (error.code === 'ECONNREFUSED') {
status = 503;
message = 'Connection refused. The daemon may not be running.';
// check for errors from the deamon
} else if (error.response) {
status = error.response.status || 500;
if (error.response.data) {
@ -21,7 +22,13 @@ module.exports = {
} else {
message = error.response;
}
// check for spee.ch thrown errors
} else if (error.message) {
status = 400;
message = error.message;
// fallback for everything else
} else {
status = 400;
message = error;
}
return [status, message];

View file

@ -18,11 +18,10 @@ module.exports = {
throw new Error('no file with key of [file] found in request');
}
},
validatePublishSubmission (file, claimName, nsfw) {
validatePublishSubmission (file, claimName) {
try {
module.exports.validateFile(file);
module.exports.validateClaimName(claimName);
module.exports.validateNSFW(nsfw);
} catch (error) {
throw error;
}
@ -76,24 +75,6 @@ module.exports = {
throw new Error('Only posts with a "Public Domain" or "Creative Commons" license are eligible for publishing through spee.ch');
}
},
cleanseNSFW (nsfw) {
switch (nsfw) {
case true:
case 'on':
case 'true':
case 1:
case '1':
return true;
case false:
case 'false':
case 'off':
case 0:
case '0':
return false;
default:
return false;
}
},
cleanseChannelName (channelName) {
if (channelName) {
if (channelName.indexOf('@') !== 0) {
@ -102,12 +83,6 @@ module.exports = {
}
return channelName;
},
validateNSFW (nsfw) {
if (nsfw === true || nsfw === false) {
return;
}
throw new Error('NSFW must be set to either true or false');
},
createPublishParams (filePath, name, title, description, license, nsfw, thumbnail, channelName) {
logger.debug(`Creating Publish Parameters`);
// provide defaults for title

View file

@ -64,20 +64,12 @@ var publishFileFunctions = {
}
},
returnNullOrChannel: function () {
const channelRadio = document.getElementById('channel-radio');
if (channelRadio.checked) {
const channelInput = document.getElementById('channel-name-select');
const radios = document.getElementsByName('anonymous-or-channel');
let anonymousOrInChannel;
// replace channelName with 'anonymous' if appropriate
for (let i = 0; i < radios.length; i++) {
if (radios[i].checked) {
anonymousOrInChannel = radios[i].value; // do whatever you want with the checked radio
break; // only one radio can be logically checked, don't check the rest
}
}
if (anonymousOrInChannel === 'anonymous') {
return null;
};
return channelInput.value.trim();
}
return null;
},
createMetadata: function() {
const nameInput = document.getElementById('claim-name-input');
@ -89,13 +81,13 @@ var publishFileFunctions = {
return {
name: nameInput.value.trim(),
channel: this.returnNullOrChannel(),
channelName: this.returnNullOrChannel(),
title: titleInput.value.trim(),
description: descriptionInput.value.trim(),
license: licenseInput.value.trim(),
nsfw: nsfwInput.checked,
type: stagedFiles[0].type,
thumbnail: thumbnailInput.value.trim()
thumbnail: thumbnailInput.value.trim(),
}
},
appendDataToFormData: function (file, metadata) {

View file

@ -4,7 +4,7 @@ const multipartMiddleware = multipart();
const db = require('../models');
const { publish } = require('../controllers/publishController.js');
const { getClaimList, resolveUri } = require('../helpers/lbryApi.js');
const { createPublishParams, validateApiPublishRequest, validatePublishSubmission, cleanseNSFW, cleanseChannelName, checkClaimNameAvailability, checkChannelAvailability } = require('../helpers/publishHelpers.js');
const { createPublishParams, validateApiPublishRequest, validatePublishSubmission, cleanseChannelName, checkClaimNameAvailability, checkChannelAvailability } = require('../helpers/publishHelpers.js');
const errorHandlers = require('../helpers/errorHandlers.js');
const { postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js');
const { authenticateChannelCredentials } = require('../auth/authentication.js');
@ -71,7 +71,9 @@ module.exports = (app) => {
});
});
// route to run a publish request on the daemon
app.post('/api/publish', multipartMiddleware, ({ body, files, ip, originalUrl }, res) => {
app.post('/api/publish', multipartMiddleware, ({ body, files, ip, originalUrl, user }, res) => {
logger.debug('api/publish body:', body);
let file, fileName, filePath, fileType, name, nsfw, license, title, description, thumbnail, anonymous, skipAuth, channelName, channelPassword;
// validate that mandatory parts of the request are present
try {
validateApiPublishRequest(body, files);
@ -81,12 +83,12 @@ module.exports = (app) => {
return;
}
// validate file, name, license, and nsfw
const file = files.file;
const fileName = file.name;
const filePath = file.path;
const fileType = file.type;
const name = body.name;
const nsfw = cleanseNSFW(body.nsfw); // cleanse nsfw input
file = files.file;
fileName = file.name;
filePath = file.path;
fileType = file.type;
name = body.name;
nsfw = (body.nsfw === 'true');
try {
validatePublishSubmission(file, name, nsfw);
} catch (error) {
@ -94,18 +96,36 @@ module.exports = (app) => {
res.status(400).json({success: false, message: error.message});
return;
}
logger.debug(`name: ${name}, nsfw: ${nsfw}`);
// optional inputs
const license = body.license || null;
const title = body.title || null;
const description = body.description || null;
const thumbnail = body.thumbnail || null;
let channelName = body.channelName || null;
license = body.license || null;
title = body.title || null;
description = body.description || null;
thumbnail = body.thumbnail || null;
anonymous = (body.channelName === 'null') || (body.channelName === undefined);
if (user) {
channelName = user.channelName || null;
} else {
channelName = body.channelName || null;
}
channelPassword = body.channelPassword || null;
skipAuth = false;
// case 1: publish from spee.ch, client logged in
if (user) {
skipAuth = true;
if (anonymous) {
channelName = null;
}
// case 2: publish from api or spee.ch, client not logged in
} else {
if (anonymous) {
skipAuth = true;
channelName = null;
}
}
channelName = cleanseChannelName(channelName);
const channelPassword = body.channelPassword || null;
logger.debug(`license: ${license} title: "${title}" description: "${description}" channelName: "${channelName}" channelPassword: "${channelPassword}" nsfw: "${nsfw}"`);
logger.debug(`name: ${name}, license: ${license} title: "${title}" description: "${description}" channelName: "${channelName}" channelPassword: "${channelPassword}" nsfw: "${nsfw}"`);
// check channel authorization
authenticateChannelCredentials(channelName, channelPassword)
authenticateChannelCredentials(skipAuth, channelName, channelPassword)
.then(result => {
if (!result) {
throw new Error('Authentication failed, you do not have access to that channel');

View file

@ -3,11 +3,11 @@
<div class="column column--10">
<form>
<div class="column column--3 column--med-10">
<input type="radio" name="anonymous-or-channel" id="anonymous-select" class="input-radio" value="anonymous" {{#unless user}}checked {{/unless}} onchange="toggleChannel(event.target.value)"/>
<label class="label label--pointer" for="anonymous-select">Anonymous</label>
<input type="radio" name="anonymous-or-channel" id="anonymous-radio" class="input-radio" value="anonymous" {{#unless user}}checked {{/unless}} onchange="toggleChannel(event.target.value)"/>
<label class="label label--pointer" for="anonymous-radio">Anonymous</label>
</div><div class="column column--7 column--med-10">
<input type="radio" name="anonymous-or-channel" id="in-a-channel-select" class="input-radio" value="in a channel" {{#if user}}checked {{/if}} onchange="toggleChannel(event.target.value)"/>
<label class="label label--pointer" for="in-a-channel-select">In a channel</label>
<input type="radio" name="anonymous-or-channel" id="channel-radio" class="input-radio" value="in a channel" {{#if user}}checked {{/if}} onchange="toggleChannel(event.target.value)"/>
<label class="label label--pointer" for="channel-radio">In a channel</label>
</div>
</form>
</div>