Authentication #170

Merged
bones7242 merged 43 commits from authentication into master 2017-09-29 02:29:22 +02:00
17 changed files with 208 additions and 156 deletions
Showing only changes of commit 53981b8618 - Show all commits

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
node_modules node_modules
.idea .idea
config/config.json

View file

@ -8,7 +8,7 @@ module.exports = {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let publishResults = {}; let publishResults = {};
// 1. make sure the name is available // 1. make sure the name is available
publishHelpers.checkNameAvailability(publishParams.name) publishHelpers.checkClaimNameAvailability(publishParams.name)
// 2. publish the file // 2. publish the file
.then(result => { .then(result => {
if (result === true) { if (result === true) {

View file

@ -100,7 +100,7 @@ module.exports = {
logger.debug(`successfully deleted ${filePath}`); logger.debug(`successfully deleted ${filePath}`);
}); });
}, },
checkNameAvailability (name) { checkClaimNameAvailability (name) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// find any records where the name is used // find any records where the name is used
db.File.findAll({ where: { name } }) db.File.findAll({ where: { name } })
@ -133,27 +133,13 @@ module.exports = {
checkChannelAvailability (name) { checkChannelAvailability (name) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// find any records where the name is used // find any records where the name is used
db.Certificate.findAll({ where: { name } }) db.User.findAll({ where: { channelName: name } })
.then(result => { .then(result => {
logger.debug('sequelize result:', result);
if (result.length >= 1) { if (result.length >= 1) {
// filter out any results that were not published from a spee.ch wallet address return resolve(false);
getWalletList()
.then((walletList) => {
const filteredResult = result.filter((claim) => {
return walletList.includes(claim.address);
});
if (filteredResult.length >= 1) {
resolve(false);
} else {
resolve(true);
}
})
.catch((error) => {
reject(error);
});
} else {
resolve(true);
} }
resolve(true);
}) })
.catch(error => { .catch(error => {
reject(error); reject(error);

View file

@ -0,0 +1,20 @@
module.exports = {
up: (queryInterface, Sequelize) => {
// logic for transforming into the new state
return queryInterface.addColumn(
'User',
'Address',
{
type : Sequelize.STRING,
allowNull: true,
}
);
},
down: (queryInterface, Sequelize) => {
// logic for reverting the changes
return queryInterface.removeColumn(
'User',
'Address'
);
},
};

View file

@ -0,0 +1,20 @@
module.exports = {
up: (queryInterface, Sequelize) => {
// logic for transforming into the new state
queryInterface.addColumn(
'Certificate',
'UserId',
{
type : Sequelize.STRING,
allowNull: false,
}
);
},
down: (queryInterface, Sequelize) => {
// logic for reverting the changes
queryInterface.removeColumn(
'Certificate',
'UserId'
);
},
};

View file

@ -0,0 +1,20 @@
module.exports = {
up: (queryInterface, Sequelize) => {
// logic for transforming into the new state
return queryInterface.addColumn(
'File',
'UserId',
{
type : Sequelize.STRING,
allowNull: true,
}
);
},
down: (queryInterface, Sequelize) => {
// logic for reverting the changes
return queryInterface.removeColumn(
'File',
'UserId'
);
},
};

View file

@ -18,6 +18,10 @@ module.exports = (sequelize, { STRING }) => {
type : STRING, type : STRING,
allowNull: false, allowNull: false,
}, },
address: {
type : STRING,
allowNull: false,
},
}, },
{ {
freezeTableName: true, freezeTableName: true,

View file

@ -39,6 +39,7 @@
"passport": "^0.4.0", "passport": "^0.4.0",
"passport-local": "^1.0.0", "passport-local": "^1.0.0",
"sequelize": "^4.1.0", "sequelize": "^4.1.0",
"sequelize-cli": "^3.0.0-3",
"sleep": "^5.1.1", "sleep": "^5.1.1",
"socket.io": "^2.0.1", "socket.io": "^2.0.1",
"socketio-file-upload": "^0.6.0", "socketio-file-upload": "^0.6.0",

View file

@ -54,16 +54,7 @@
width: 90% width: 90%
} }
.input-text--primary {
border: 0px;
background-color: #ffffff;
border-bottom: 1px solid grey;
}
.input-text--primary:focus {
outline: none;
border-bottom: 1px solid blue;
}
/* show routes */ /* show routes */
.show-asset { .show-asset {

View file

@ -123,12 +123,36 @@ table {
word-wrap: break-word; word-wrap: break-word;
} }
.input-error { /* BEM */
.info-message {
font-weight: bold; font-weight: bold;
color: red;
font-size: small;
} }
.info-message--success {
color: green;
}
.info-message--failure {
color: red;
}
.input-text {
outline: none;
border: 0px;
background-color: #ffffff;
}
kauffj commented 2017-09-22 15:53:10 +02:00 (Migrated from github.com)
Review

What if I'm not on Chrome?

What if I'm not on Chrome?
.input-text--primary {
border-bottom: 1px solid grey;
}
.input-text--primary:focus {
border-bottom: 1px solid blue;
}
/* MEDIA QUERIES */
@media (max-width: 1250px) { @media (max-width: 1250px) {
.wrapper { .wrapper {

View file

@ -55,18 +55,6 @@ function dataURItoBlob(dataURI) {
return new Blob([ia], {type:mimeString}); return new Blob([ia], {type:mimeString});
} }
function showError(elementId, errorMsg) {
var errorDisplay = document.getElementById(elementId);
errorDisplay.hidden = false;
errorDisplay.innerText = errorMsg;
}
function clearError(elementId) {
var errorDisplay = document.getElementById(elementId);
errorDisplay.hidden = true;
errorDisplay.innerText = '';
}
// Create new error objects, that prototypically inherit from the Error constructor // Create new error objects, that prototypically inherit from the Error constructor
function FileError(message) { function FileError(message) {
this.name = 'FileError'; this.name = 'FileError';

View file

@ -27,56 +27,6 @@ function validateFile(file) {
throw new Error(file.type + ' is not a supported file type. Only, .jpeg, .png, .gif, and .mp4 files are currently supported.') throw new Error(file.type + ' is not a supported file type. Only, .jpeg, .png, .gif, and .mp4 files are currently supported.')
} }
} }
// validation function that checks to make sure the claim name is not already claimed
function isChannelAvailable (name) {
return new Promise(function(resolve, reject) {
// make sure the claim name is still available
var xhttp;
xhttp = new XMLHttpRequest();
xhttp.open('GET', '/api/isChannelAvailable/' + name, true);
xhttp.responseType = 'json';
xhttp.onreadystatechange = function() {
if (this.readyState == 4 ) {
if ( this.status == 200) {
if (this.response == true) {
resolve();
} else {
reject( new NameError("That name has already been claimed by another user. Please choose a different name."));
}
} else {
reject("request to check claim name failed with status:" + this.status);
};
}
};
xhttp.send();
});
}
// validation function that checks to make sure the claim name is not already claimed
function isNameAvailable (name) {
return new Promise(function(resolve, reject) {
// make sure the claim name is still available
var xhttp;
xhttp = new XMLHttpRequest();
xhttp.open('GET', '/api/isClaimAvailable/' + name, true);
xhttp.responseType = 'json';
xhttp.onreadystatechange = function() {
if (this.readyState == 4 ) {
if ( this.status == 200) {
if (this.response == true) {
resolve();
} else {
reject( new NameError("That name has already been claimed by another user. Please choose a different name."));
}
} else {
reject("request to check claim name failed with status:" + this.status);
};
}
};
xhttp.send();
});
}
// validation function that checks to make sure the claim name is valid // validation function that checks to make sure the claim name is valid
function validateClaimName (name) { function validateClaimName (name) {
// ensure a name was entered // ensure a name was entered
@ -95,51 +45,85 @@ function cleanseClaimName(name) {
name = name.replace(/[^A-Za-z0-9-]/g, ''); // remove all characters that are not A-Z, a-z, 0-9, or '-' name = name.replace(/[^A-Za-z0-9-]/g, ''); // remove all characters that are not A-Z, a-z, 0-9, or '-'
return name; return name;
} }
// validaiton function to check claim name as the input changes
function checkClaimName(name){ // validation functions to check claim & channel name eligibility as the inputs change
try {
// check to make sure the characters are valid function isNameAvailable (name, apiUrl) {
validateClaimName(name); return new Promise(function(resolve, reject) {
clearError('input-error-claim-name'); // make sure the claim name is still available
// check to make sure it is availabe var xhttp;
isNameAvailable(name) xhttp = new XMLHttpRequest();
.then(function() { xhttp.open('GET', apiUrl + name, true);
document.getElementById('claim-name-available').hidden = false; xhttp.responseType = 'json';
}) xhttp.onreadystatechange = function() {
.catch(function(error) { if (this.readyState == 4 ) {
document.getElementById('claim-name-available').hidden = true; if ( this.status == 200) {
showError('input-error-claim-name', error.message); if (this.response == true) {
}); resolve();
} catch (error) { } else {
showError('input-error-claim-name', error.message); reject( new NameError("That name has already been claimed by another user. Please choose a different name."));
document.getElementById('claim-name-available').hidden = true; }
} } else {
reject("request to check claim name failed with status:" + this.status);
};
}
};
xhttp.send();
});
} }
function showError(errorDisplay, errorMsg) {
errorDisplay.hidden = false;
errorDisplay.innerText = errorMsg;
}
// validaiton function to check claim name as the input changes function hideError(errorDisplay) {
function checkChannelName(event){ errorDisplay.hidden = true;
console.log(event); errorDisplay.innerText = '';
const name = event.target.value; }
const target = document.getElementById(event.target.id);
const errorDisplay = target.parentNode.firstChild; function showSuccess (successElement) {
console.log('error display:', errorDisplay) successElement.hidden = false;
successElement.innerHTML = "&#x2714";
}
function hideSuccess (successElement) {
successElement.hidden = true;
successElement.innerHTML = "";
}
function checkAvailability(name, successDisplayElement, errorDisplayElement, isNameAvailable, apiUrl) {
try { try {
// check to make sure the characters are valid
validateClaimName(name);
// check to make sure it is available // check to make sure it is available
isChannelAvailable(name) isNameAvailable(name, apiUrl)
.then(function() { .then(function() {
errorDisplay.hidden = false; hideError(errorDisplayElement);
showSuccess(successDisplayElement)
}) })
.catch(function(error) { .catch(function(error) {
errorDisplay.hidden = false; hideSuccess(successDisplayElement);
showError(errorDisplay.getAttribute('id'), error.message); showError(errorDisplayElement, error.message);
}); });
} catch (error) { } catch (error) {
console.log(error.message); hideSuccess(successDisplayElement);
document.getElementById(errorDisplay.getAttribute('id')).hidden = true; showError(errorDisplayElement, error.message);
} }
} }
function checkClaimName(name){
const successDisplayElement = document.getElementById('claim-name-success');
const errorDisplayElement = document.getElementById('claim-name-error');
checkAvailability(name, successDisplayElement, errorDisplayElement, isNameAvailable, '/api/isClaimAvailable/');
}
function checkChannelName(name){
const successDisplayElement = document.getElementById('channel-name-success');
const errorDisplayElement = document.getElementById('channel-name-error');
checkAvailability(name, successDisplayElement, errorDisplayElement, isNameAvailable, '/api/isChannelAvailable/');
}
// validation function which checks all aspects of the publish submission // validation function which checks all aspects of the publish submission
function validateSubmission(stagedFiles, name){ function validateSubmission(stagedFiles, name){
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {

View file

@ -3,7 +3,7 @@ const multipart = require('connect-multiparty');
const multipartMiddleware = multipart(); const multipartMiddleware = multipart();
const { publish } = require('../controllers/publishController.js'); const { publish } = require('../controllers/publishController.js');
const { getClaimList, resolveUri } = require('../helpers/lbryApi.js'); const { getClaimList, resolveUri } = require('../helpers/lbryApi.js');
const { createPublishParams, validateFile, checkNameAvailability, checkChannelAvailability } = require('../helpers/publishHelpers.js'); const { createPublishParams, validateFile, checkClaimNameAvailability, checkChannelAvailability } = require('../helpers/publishHelpers.js');
const errorHandlers = require('../helpers/errorHandlers.js'); const errorHandlers = require('../helpers/errorHandlers.js');
const { postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js'); const { postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js');
@ -25,7 +25,7 @@ module.exports = (app, hostedContentPath) => {
// route to check whether spee.ch has published to a claim // route to check whether spee.ch has published to a claim
app.get('/api/isClaimAvailable/:name', ({ ip, originalUrl, params }, res) => { app.get('/api/isClaimAvailable/:name', ({ ip, originalUrl, params }, res) => {
// send response // send response
checkNameAvailability(params.name) checkClaimNameAvailability(params.name)
.then(result => { .then(result => {
if (result === true) { if (result === true) {
res.status(200).json(true); res.status(200).json(true);
@ -39,8 +39,7 @@ module.exports = (app, hostedContentPath) => {
}); });
}); });
// route to check whether spee.ch has published to a channel // route to check whether spee.ch has published to a channel
app.get('/api/isChannelAvailable/:name', ({ ip, originalUrl, params }, res) => { app.get('/api/isChannelAvailable/:name', ({ params }, res) => {
// send response
checkChannelAvailability(params.name) checkChannelAvailability(params.name)
.then(result => { .then(result => {
if (result === true) { if (result === true) {
@ -51,6 +50,7 @@ module.exports = (app, hostedContentPath) => {
} }
}) })
.catch(error => { .catch(error => {
logger.debug('api/isChannelAvailable/ error', error);
res.status(500).json(error); res.status(500).json(error);
}); });
}); });

View file

@ -7,11 +7,11 @@
<form id="login-form" action="/login" method="post"> <form id="login-form" action="/login" method="post">
<div> <div>
<label>Username:</label> <label>Username:</label>
@ <input type="text" name="username" class="input-text--primary"/> @ <input type="text" name="username" class="input-text input-text--primary"/>
</div> </div>
<div> <div>
<label>Password:</label> <label>Password:</label>
<input type="password" name="password" class="input-text--primary"/> <input type="password" name="password" class="input-text input-text--primary"/>
</div> </div>
<div> <div>
<input type="submit" value="Log In"/> <input type="submit" value="Log In"/>
@ -23,11 +23,11 @@
<form action="/signup" method="post"> <form action="/signup" method="post">
<div> <div>
<label>Channel name:</label> <label>Channel name:</label>
@ <input type="text" name="username" class="input-text--primary"/> @ <input type="text" name="username" class="input-text input-text--primary"/>
</div> </div>
<div> <div>
<label>Password:</label> <label>Password:</label>
<input type="password" name="password" class="input-text--primary"/> <input type="password" name="password" class="input-text input-text--primary"/>
</div> </div>
<div> <div>
<input type="submit" value="Create"/> <input type="submit" value="Create"/>

View file

@ -1,21 +1,34 @@
<div id="claim-channel-input-area"> <div id="claim-channel-input-area">
<label for="publish-channel">Channel:</label></td>
<select type="text" id="publish-channel" name="channel" value="channel" onclick="check(event)"> <p>
{{#if user}} <label for="publish-channel">Channel:</label></td>
<option value="@{{user.channelName}}" >@{{user.channelName}}</option> <select type="text" id="publish-channel" name="channel" value="channel" onclick="check(event)">
{{/if}} {{#if user}}
<option value="@speech" >Anonymous</option> <option value="@{{user.channelName}}" >@{{user.channelName}}</option>
<option value="new" >New</option> {{/if}}
</select> <option value="@speech" >Anonymous</option>
<div id="channel-create-details" hidden="true"><p id="test" style="color: red;"></p> <option value="new" >New</option>
<label for="channelName">Channel Name: </label> </select>
@<input type="text" id="channel-name-input" class="input-text--primary" oninput="checkChannelName(event)"> </p>
<br/>
<label for="password" >Password: </label> <div id="channel-create-details" hidden="true">
<input type="text" id="password" class="input-text--primary">
<br/> <span id="channel-name-error" class="info-message info-message--failure"></span>
<button >create</button> <p>
<label for="channelName">Channel Name: </label>
@<input type="text" id="channel-name-input" class="input-text input-text--primary" placeholder="exampleChannel" oninput="checkChannelName(event.target.value)">
<span id="channel-name-success" class="info-message info-message--success"></span>
<br/>
<label for="password" >Password: </label>
<input type="password" id="password" placeholder="" class="input-text input-text--primary">
<br/>
</p>
<button >create</button>
</div> </div>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">

View file

@ -5,7 +5,7 @@
<table> <table>
<tr> <tr>
<td><label for="publish-title">Title: </label></td> <td><label for="publish-title">Title: </label></td>
<td><input type="text" id="publish-title" class="input-text--primary"></td> <td><input type="text" id="publish-title" class="input-text input-text--primary"></td>
</tr> </tr>
<tr> <tr>
<td><label for="publish-description">Description: </label></td> <td><label for="publish-description">Description: </label></td>

View file

@ -11,12 +11,12 @@
</div> </div>
<div class="col-right"> <div class="col-right">
<div id="publish-active-area"> <div id="publish-active-area">
<div class="input-error" id="input-error-claim-name" hidden="true"></div>
<div class="stop-float"> <div class="stop-float">
<span id="claim-name-error" class="info-message info-message--failure" hidden="true"></span>
<p> <p>
Spee.ch/ Spee.ch/
<input type="text" id="claim-name-input" class="input-text--primary" placeholder="your-url-here" oninput="checkClaimName(event.target.value)"> <input type="text" id="claim-name-input" class="input-text input-text--primary" placeholder="your-url-here" oninput="checkClaimName(event.target.value)">
<span id="claim-name-available" hidden="true" style="color: green">&#x2714</span> <span id="claim-name-success" class="info-message info-message--success"></span>
</p> </p>
</div> </div>
<div class="stop-float"> <div class="stop-float">
@ -55,6 +55,6 @@
document.getElementById('input-error-file-selection').innerHTML = ''; document.getElementById('input-error-file-selection').innerHTML = '';
document.getElementById('input-error-claim-name').innerHTML = ''; document.getElementById('input-error-claim-name').innerHTML = '';
document.getElementById('input-error-publish-submit').innerHTML = ''; document.getElementById('input-error-publish-submit').innerHTML = '';
document.getElementById('claim-name-available').hidden = true; document.getElementById('claim-name-success').hidden = true;
} }
</script> </script>