Apply Javascript styleguide

This commit is contained in:
Jonathan Cremin 2015-08-23 22:12:32 +01:00
parent 752ce964c8
commit 6e0f351093
30 changed files with 364 additions and 375 deletions

View file

@ -4,7 +4,6 @@ import csrf from 'koa-csrf';
import views from 'koa-views';
import stats from 'koa-statsd';
import * as redis from '../lib/redis';
import co from 'co';
import StatsD from 'statsy';
// waiting for PR to be merged, can remove swig dependency when done
import errors from '../lib/koa-error';
@ -13,29 +12,26 @@ import * as file from './routes/file';
import * as pro from './routes/pro';
import * as user from './routes/user';
import debugname from 'debug';
const debug = debugname('hostr-web');
const router = new Router();
router.use(errors({template: path.join(__dirname, 'public', 'error.html')}));
let statsdOpts = {prefix: 'hostr-web', host: process.env.STATSD_HOST || 'localhost'};
const statsdOpts = {prefix: 'hostr-web', host: process.env.STATSD_HOST || 'localhost'};
router.use(stats(statsdOpts));
let statsd = new StatsD(statsdOpts);
router.use(function* (next) {
const statsd = new StatsD(statsdOpts);
router.use(function* statsMiddleware(next) {
this.statsd = statsd;
yield next;
});
router.use(redis.sessionStore());
router.use(function* (next) {
router.use(function* stateMiddleware(next) {
this.state = {
session: this.session,
apiURL: process.env.API_URL,
baseURL: process.env.BASE_URL,
stripePublic: process.env.STRIPE_PUBLIC_KEY
stripePublic: process.env.STRIPE_PUBLIC_KEY,
};
yield next;
});
@ -43,7 +39,7 @@ router.use(function* (next) {
router.use(csrf());
router.use(views('views', {
default: 'ejs'
default: 'ejs',
}));
router.get('/', index.main);
@ -76,14 +72,14 @@ router.get('/:id', file.landing);
router.get('/file/:id/:name', file.get);
router.get('/file/:size/:id/:name', file.get);
router.get('/files/:id/:name', file.get);
router.get('/download/:id/:name', function* (id) {
router.get('/download/:id/:name', function* downloadRedirect(id) {
this.redirect('/' + id);
});
router.get('/updaters/mac', function* () {
router.get('/updaters/mac', function* macUpdater() {
this.redirect('/updaters/mac.xml');
});
router.get('/updaters/mac/changelog', function* () {
router.get('/updaters/mac/changelog', function* macChangelog() {
yield this.render('mac-update-changelog');
});

View file

@ -7,14 +7,13 @@ import debugname from 'debug';
const debug = debugname('hostr-web:auth');
import { Mandrill } from 'mandrill-api/mandrill';
const mandrill = new Mandrill(process.env.MANDRILL_KEY);
import mongo from '../../lib/mongo';
export function* authenticate(email, password) {
const Users = this.db.Users;
const Logins = this.db.Logins;
const remoteIp = this.headers['x-real-ip'] || this.ip;
if (!password || password.length < 6){
if (!password || password.length < 6) {
debug('No password, or password too short');
return new Error('Invalid login details');
}
@ -33,11 +32,10 @@ export function* authenticate(email, password) {
login.successful = true;
yield Logins.updateOne({_id: login._id}, login);
return user;
} else {
debug('Password invalid');
login.successful = false;
yield Logins.updateOne({_id: login._id}, login);
}
debug('Password invalid');
login.successful = false;
yield Logins.updateOne({_id: login._id}, login);
} else {
debug('Email invalid');
login.successful = false;
@ -58,9 +56,9 @@ export function* setupSession(user) {
'maxFileSize': 20971520,
'joined': user.joined,
'plan': user.type || 'Free',
'uploadsToday': yield this.db.Files.count({owner: user._id, 'time_added': {'$gt': Math.ceil(Date.now()/1000)-86400}}),
'uploadsToday': yield this.db.Files.count({owner: user._id, 'time_added': {'$gt': Math.ceil(Date.now() / 1000) - 86400}}),
'token': token,
'md5': crypto.createHash('md5').update(user.email).digest('hex')
'md5': crypto.createHash('md5').update(user.email).digest('hex'),
};
if (sessionUser.plan === 'Pro') {
@ -71,7 +69,7 @@ export function* setupSession(user) {
this.session.user = sessionUser;
if (this.request.body.remember && this.request.body.remember === 'on') {
const Remember = this.db.Remember;
var rememberToken = uuid();
const rememberToken = uuid();
Remember.save({_id: rememberToken, 'user_id': user.id, created: new Date().getTime()});
this.cookies.set('r', rememberToken, { maxAge: 1209600000, httpOnly: true});
}
@ -87,12 +85,12 @@ export function* signup(email, password, ip) {
throw new Error('Email already in use.');
}
const cryptedPassword = yield passwords.crypt(password);
var user = {
const user = {
email: email,
'salted_password': cryptedPassword,
joined: Math.round(new Date().getTime() / 1000),
'signup_ip': ip,
activationCode: uuid()
activationCode: uuid(),
};
Users.insertOne(user);
@ -112,11 +110,11 @@ ${process.env.BASE_URL + '/activate/' + user.activationCode}
'from_name': 'Jonathan from Hostr',
to: [{
email: user.email,
type: 'to'
type: 'to',
}],
'tags': [
'user-activation'
]
'user-activation',
],
}});
}
@ -126,11 +124,11 @@ export function* sendResetToken(email) {
const Reset = this.db.Reset;
const user = yield Users.findOne({email: email});
if (user) {
var token = uuid.v4();
const token = uuid.v4();
Reset.save({
'_id': user._id,
'token': token,
'created': Math.round(new Date().getTime() / 1000)
'created': Math.round(new Date().getTime() / 1000),
});
const html = yield render('email/inlined/forgot', {forgotUrl: process.env.BASE_URL + '/forgot/' + token});
const text = `It seems you've forgotten your password :(
@ -144,11 +142,11 @@ Visit ${process.env.BASE_URL + '/forgot/' + token} to set a new one.
'from_name': 'Jonathan from Hostr',
to: [{
email: user.email,
type: 'to'
type: 'to',
}],
'tags': [
'password-reset'
]
'password-reset',
],
}});
} else {
throw new Error('There was an error looking up your email address.');

3
web/public/.eslintignore Normal file
View file

@ -0,0 +1,3 @@
jspm_packages/
config.js
lazy-src.js

View file

@ -1,11 +1,11 @@
import angular from 'angular';
import ngRoute from 'angular/route';
import ngResource from 'angular/resource';
import ReconnectingWebSocket from 'angular-reconnecting-websocket';
import ngDimensions from 'angular-strap/dist/modules/dimensions';
import ngStrapCore from 'angular-strap/dist/modules/compiler';
import ngTooltip from 'angular-strap/dist/modules/tooltip';
import ngTooltipTemplate from 'angular-strap/dist/modules/tooltip.tpl';
import 'angular/route';
import 'angular/resource';
import 'angular-reconnecting-websocket';
import 'angular-strap/dist/modules/dimensions';
import 'angular-strap/dist/modules/compiler';
import 'angular-strap/dist/modules/tooltip';
import 'angular-strap/dist/modules/tooltip.tpl';
import { FilesController, FileController, AccountController, ProController, BillingController } from './app/controllers';
import { appHeader, appFooter, menuDropdown, searchShortcut, stripeSubscribe } from './app/directives';
@ -15,12 +15,12 @@ import { fileSize, direct } from './app/filters';
import { FileService, UserService, EventService, TransactionService, SettingService } from './app/services';
// Declare app level module which depends on filters, and services
var app = angular.module('hostr', [
const app = angular.module('hostr', [
'ngRoute',
'ngResource',
'reconnectingWebSocket',
'mgcrea.ngStrap.core',
'mgcrea.ngStrap.tooltip'
'mgcrea.ngStrap.tooltip',
]);
app.factory('FileService', ['$resource', '$cacheFactory', FileService.factory]);
@ -40,21 +40,20 @@ app.directive('lazySrc', ['$window', '$document', lazySrc]);
app.directive('searchShortcut', ['$document', searchShortcut]);
app.directive('stripeSubscribe', ['$http', stripeSubscribe]);
app.config(['$routeProvider', '$locationProvider', '$httpProvider', '$tooltipProvider', function($routeProvider, $locationProvider, $httpProvider, $tooltipProvider) {
app.config(['$routeProvider', '$locationProvider', '$httpProvider', ($routeProvider, $locationProvider, $httpProvider) => {
if (typeof window.user !== 'undefined') {
$httpProvider.defaults.headers.common.Authorization = ':' + window.user.token;
}
$locationProvider.html5Mode(true);
$httpProvider.interceptors.push(['$q', function($q) {
$httpProvider.interceptors.push(['$q', ($q) => {
return {
responseError: function(rejection) {
responseError: (rejection) => {
if (rejection.status === 401) {
window.location = '/logout';
}
return $q.reject(rejection);
}
},
};
}]);
@ -63,66 +62,65 @@ app.config(['$routeProvider', '$locationProvider', '$httpProvider', '$tooltipPro
controller: FilesController,
title: ' - Files',
resolve: {
files: ['FileService', function(Files) {
files: ['FileService', (Files) => {
return Files.query();
}]
}
}],
},
})
.when('/apps', {
templateUrl: '/build/partials/apps.html',
title: ' - Apps for Mac and Windows'
title: ' - Apps for Mac and Windows',
})
.when('/pro', {
templateUrl: '/build/partials/pro.html',
controller: ProController,
title: ' - Pro'
title: ' - Pro',
})
.when('/account', {
templateUrl: '/build/partials/account.html',
controller: AccountController,
title: ' - Account'
title: ' - Account',
})
.when('/billing', {
templateUrl: '/build/partials/billing.html',
controller: BillingController,
title: ' - Billing'
title: ' - Billing',
})
.when('/terms', {
templateUrl: '/build/partials/terms.html',
title: ' - Terms of Service'
title: ' - Terms of Service',
})
.when('/privacy', {
templateUrl: '/build/partials/privacy.html',
title: ' - Privacy Policy'
title: ' - Privacy Policy',
})
.when('/:id', {
templateUrl: '/build/partials/file.html',
controller: FileController,
resolve: {
file: ['$route', 'FileService', function($route, Files) {
file: ['$route', 'FileService', ($route, Files) => {
return Files.get({id: $route.current.params.id});
}]
}
}],
},
});
}]);
app.run(['$location', '$rootScope', function($location, $rootScope) {
$rootScope.$on('$routeChangeStart', function(e, curr) {
if (curr.$$route && curr.$$route.resolve) {
app.run(['$location', '$rootScope', ($location, $rootScope) => {
$rootScope.$on('$routeChangeStart', (e, curr) => {
if (curr.$$route && curr.$$route.resolve) {
// Show a loading message until promises are resolved
$rootScope.loadingView = true;
}
});
$rootScope.$on('$routeChangeSuccess', function (event, current) {
$rootScope.loadingView = true;
}
});
$rootScope.$on('$routeChangeSuccess', (event, current) => {
$rootScope.navError = false;
$rootScope.pageTitle = current.$$route.title;
});
$rootScope.$on('$routeChangeError', function () {
$rootScope.$on('$routeChangeError', () => {
$rootScope.loadingView = false;
$rootScope.navError = true;
});
$rootScope.$on('$locationChangeStart', function(event, newUrl) {
$rootScope.$on('$locationChangeStart', (event, newUrl) => {
if (window.ga) {
window.ga('send', 'pageview', newUrl);
}

View file

@ -1,17 +1,17 @@
export class FilesController {
constructor($scope, UserService, EventService, files) {
$scope.$root.user = UserService.get();
files.$promise.then(function() {
files.$promise.then(() => {
$scope.$root.loadingView = false;
});
$scope.header = 'full';
if (!$scope.$root.files) {
$scope.$root.files = files;
}
$scope.remove = function(file) {
$scope.$root.files.some(function(existingFile, index) {
$scope.remove = (file) => {
$scope.$root.files.some((existingFile, index) => {
if (file.id === existingFile.id) {
file.$remove(function() {
file.$remove(() => {
$scope.$root.showDropdown = false;
$scope.$root.files.splice(index, 1);
});
@ -25,8 +25,8 @@ export class FilesController {
FilesController.$inject = ['$scope', 'UserService', 'EventService', 'files'];
export class FileController {
constructor ($scope, $rootScope, $routeParams, ReconnectingWebSocket, file) {
file.$promise.then(function() {
constructor($scope, $rootScope, $routeParams, ReconnectingWebSocket, file) {
file.$promise.then(() => {
$scope.$root.loadingView = false;
$scope.header = 'small';
$scope.file = file;
@ -34,25 +34,25 @@ export class FileController {
$rootScope.pageTitle = ' - ' + file.name;
if (file.status === 'uploading') {
file.percent = 0;
var ws = new ReconnectingWebSocket(window.settings.apiURL.replace(/^http/, 'ws') + '/file/' + file.id);
ws.onmessage = function (msg) {
var evt = JSON.parse(msg.data);
const ws = new ReconnectingWebSocket(window.settings.apiURL.replace(/^http/, 'ws') + '/file/' + file.id);
ws.onmessage = (msg) => {
const evt = JSON.parse(msg.data);
$rootScope.$broadcast(evt.type, evt.data);
};
ws.onopen = function() {
ws.onopen = () => {
ws.send(JSON.stringify({authorization: window.user.token}));
};
$rootScope.$on('file-progress', function(evt, data) {
$rootScope.$on('file-progress', (evt, data) => {
$scope.file.percent = data.complete;
});
$rootScope.$on('file-added', function(evt, data) {
$rootScope.$on('file-added', (evt, data) => {
$scope.file = data;
});
$rootScope.$on('file-accepted', function(evt, data) {
$rootScope.$on('file-accepted', (evt, data) => {
$scope.file = data;
});
}
}, function() {
}, () => {
$rootScope.navError = true;
$scope.$root.loadingView = false;
});
@ -61,15 +61,15 @@ export class FileController {
FileController.$inject = ['$scope', '$rootScope', '$routeParams', 'WebSocket', 'file'];
export class ProController {
constructor ($scope, $http, UserService) {
constructor($scope, $http, UserService) {
$scope.$root.loadingView = false;
$scope.user = UserService.get();
$scope.header = 'full';
$scope.cancel = function() {
$http.post('/pro/cancel').success(function() {
$scope.cancel = () => {
$http.post('/pro/cancel').success(() => {
window.location.reload(true);
}).error(function(data) {
console.log(new Error(data));
}).error((data) => {
console.error(new Error(data));
});
};
}
@ -77,17 +77,17 @@ export class ProController {
ProController.$inject = ['$scope', '$http', 'UserService'];
export class AccountController {
constructor ($scope, UserService, SettingService) {
constructor($scope, UserService, SettingService) {
$scope.$root.loadingView = false;
$scope.$root.user = UserService.get();
$scope.submit = function(form) {
$scope.submit = (form) => {
$scope.updated = false;
$scope.error = false;
SettingService.update(form).then(function() {
SettingService.update(form).then(() => {
$scope.updated = true;
delete $scope.user.new_password;
delete $scope.user.current_password;
}, function(response) {
}, (response) => {
$scope.error = response.data.error.message;
});
};
@ -96,7 +96,7 @@ export class AccountController {
AccountController.$inject = ['$scope', 'UserService', 'SettingService'];
export class BillingController {
constructor ($scope, UserService, TransactionService) {
constructor($scope, UserService, TransactionService) {
$scope.$root.loadingView = false;
$scope.$root.user = UserService.get();
$scope.transactions = TransactionService.query();

View file

@ -9,7 +9,7 @@ export function appHeader() {
scope.userMD5 = window.user.md5;
scope.email = window.user.email;
scope.pro = (window.user.type === 'Pro');
}
},
};
}
@ -23,19 +23,19 @@ export function appFooter() {
scope.userMD5 = window.user.md5;
scope.email = window.user.email;
scope.pro = (window.user.type === 'Pro');
}
},
};
}
export function menuDropdown() {
return function($scope, element) {
return ($scope, element) => {
$scope.$root.overlayClick = function overlayClick() {
$scope.$root.showDropdown = false;
$('.dropdown').hide();
};
var activeDropdown = $(element).find('.dropdown');
element.on('click', function(e) {
const activeDropdown = $(element).find('.dropdown');
element.on('click', (e) => {
if (activeDropdown.not(':visible').length > 0) {
$('.dropdown').hide();
$scope.$root.showDropdown = true;
@ -50,10 +50,10 @@ export function menuDropdown() {
}
export function searchShortcut ($document) {
return function($scope, element) {
$document.bind('keypress', function(event) {
if(event.which === 47) {
export function searchShortcut($document) {
return ($scope, element) => {
$document.bind('keypress', (event) => {
if (event.which === 47) {
if (['INPUT', 'TEXTAREA'].indexOf(document.activeElement.tagName) < 0) {
element[0].focus();
event.preventDefault();
@ -68,21 +68,23 @@ export function stripeSubscribe($http) {
const handler = window.StripeCheckout.configure({
key: window.settings.stripePublic,
image: '/images/stripe-128.png',
token: function(token) {
$http.post('/pro/create', {stripeToken: token})
.success(function(data) {
token: (token) => {
$http.post('/pro/create', {
stripeToken: token,
})
.success((data) => {
if (data.status === 'active') {
window.user.plan = 'Pro';
window.location.reload(true);
}
})
.error(function() {
alert('Error upgrading your account');
.error(() => {
console.error('Error upgrading your account');
});
}
},
});
return function(scope, element) {
element.on('click', function() {
return (scope, element) => {
element.on('click', () => {
// Open Checkout with further options
handler.open({
name: 'Hostr',
@ -91,7 +93,7 @@ export function stripeSubscribe($http) {
amount: 600,
currency: 'USD',
panelLabel: 'Subscribe {{amount}}',
billingAddress: false
billingAddress: false,
});
});
};

View file

@ -11,56 +11,56 @@ function guid() {
}
export default function dropzone(FileService, $cacheFactory) {
var dropOverlay = document.getElementById('filedrop-overlay');
var dropzoneEl;
var errorTimeout;
return function($scope) {
$scope.$on('$viewContentLoaded', function() {
const dropOverlay = document.getElementById('filedrop-overlay');
let dropzoneEl;
let errorTimeout;
return ($scope) => {
$scope.$on('$viewContentLoaded', () => {
if (!dropzoneEl) {
$scope.$root.uploadingFiles = [];
var clickable = [].slice.call(document.querySelectorAll('.choose-file'));
const clickable = [].slice.call(document.querySelectorAll('.choose-file'));
dropzoneEl = new Dropzone(document.body, {
url: window.settings.apiURL + '/file',
maxFilesize: window.user.maxFileSize / 1024 / 1024,
maxThumbnailFilesize: 5,
thumbnailWidth: 150,
thumbnailHeight: 98,
parallelUploads: 1,
uploadMultiple: false,
clickable: clickable.length ? clickable : false,
autoDiscover: false,
headers: {'Authorization': ':' + window.user.token},
previewsContainer: false
url: window.settings.apiURL + '/file',
maxFilesize: window.user.maxFileSize / 1024 / 1024,
maxThumbnailFilesize: 5,
thumbnailWidth: 150,
thumbnailHeight: 98,
parallelUploads: 1,
uploadMultiple: false,
clickable: clickable.length ? clickable : false,
autoDiscover: false,
headers: {'Authorization': ':' + window.user.token},
previewsContainer: false,
});
dropzoneEl.on('thumbnail', function(file, thumbnail){
dropzoneEl.on('thumbnail', (file, thumbnail) => {
file.thumbnail = thumbnail;
$scope.$apply();
});
dropzoneEl.on('addedfile', function(file){
var id = guid();
dropzoneEl.on('addedfile', (file) => {
const id = guid();
file.guid = id;
$scope.$root.uploadingFiles.push(file);
$scope.$apply();
});
dropzoneEl.on('sending', function(file, xhr) {
dropzoneEl.on('sending', (file, xhr) => {
xhr.setRequestHeader('hostr-guid', file.guid);
});
dropzoneEl.on('uploadprogress', function(file, progress) {
dropzoneEl.on('uploadprogress', (file, progress) => {
$scope.$root.progress = {
name: file.name,
percent: progress,
status: 'Uploading'
status: 'Uploading',
};
if (progress === 100) {
$scope.$root.progress.status = 'Processing';
}
$scope.$apply();
});
dropzoneEl.on('complete', function(file){
dropzoneEl.on('complete', (file) => {
delete $scope.$root.progress;
$scope.$apply();
$scope.$root.uploadingFiles.some(function(uploadingFile, index) {
$scope.$root.uploadingFiles.some((uploadingFile, index) => {
if (uploadingFile.guid === file.guid) {
$scope.$root.uploadingFiles.splice(index, 1);
$scope.$apply();
@ -69,11 +69,10 @@ export default function dropzone(FileService, $cacheFactory) {
return false;
});
});
dropzoneEl.on('error', function(evt, error){
dropzoneEl.on('error', (evt, error) => {
if (error.error) {
$scope.$root.uploadError = 'Error uploading file: ' + evt.name + '. ' + error.error.message;
}
else if (evt.name) {
} else if (evt.name) {
$scope.$root.uploadError = 'Error uploading file: ' + evt.name + '. ' + error;
} else {
if (error[0] !== '<') {
@ -82,33 +81,33 @@ export default function dropzone(FileService, $cacheFactory) {
}
$scope.$apply();
clearTimeout(errorTimeout);
errorTimeout = setTimeout(function() {
errorTimeout = setTimeout(() => {
$scope.$root.uploadError = '';
$scope.$apply();
}, 5000);
});
var addFile = function(newFile) {
if (!$scope.$root.files.some(function (file) {
return file.id === newFile.id;
})) {
var cache = $cacheFactory.get('files-cache');
const addFile = (newFile) => {
if (!$scope.$root.files.some((file) => {
return file.id === newFile.id;
})) {
const cache = $cacheFactory.get('files-cache');
cache.removeAll();
var file = new FileService(newFile);
const file = new FileService(newFile);
$scope.$root.files.unshift(file);
$scope.$root.user.uploads_today++;
$scope.$apply();
}
};
dropzoneEl.on('success', function(file, response){
dropzoneEl.on('success', (file, response) => {
addFile(response);
});
$scope.$on('file-added', function(event, data){
$scope.$on('file-added', (event, data) => {
addFile(data);
});
$scope.$on('file-accepted', function(event, data){
$scope.$root.uploadingFiles.some(function(file) {
$scope.$on('file-accepted', (event, data) => {
$scope.$root.uploadingFiles.some((file) => {
if (file.guid === data.guid) {
file.id = data.id;
file.href = data.href;
@ -117,33 +116,33 @@ export default function dropzone(FileService, $cacheFactory) {
}
});
});
$scope.$on('file-deleted', function(evt, data) {
$scope.$root.files.forEach(function(file, index) {
if(data.id === file.id) {
$scope.$on('file-deleted', (evt, data) => {
$scope.$root.files.forEach((file, index) => {
if (data.id === file.id) {
delete $scope.$root.files[index];
$scope.$digest();
}
});
});
document.body.addEventListener('dragenter', function(){
document.body.addEventListener('dragenter', () => {
dropOverlay.style.display = 'block';
});
dropOverlay.addEventListener('dragleave', function(event){
dropOverlay.addEventListener('dragleave', (event) => {
if (event.target.outerText !== 'Drop files to upload' || event.x === 0) {
dropOverlay.style.display = 'none';
}
});
dropOverlay.addEventListener('drop', function(){
dropOverlay.addEventListener('drop', () => {
dropOverlay.style.display = 'none';
});
} else {
var clicker = [].slice.call(document.querySelectorAll('.choose-file'));
const clicker = [].slice.call(document.querySelectorAll('.choose-file'));
if (clicker) {
clicker.forEach(function(el) {
el.addEventListener('click', function() {
clicker.forEach((el) => {
el.addEventListener('click', () => {
return dropzoneEl.hiddenFileInput.click();
});
});

View file

@ -1,33 +1,29 @@
export function fileSize() {
return function(input) {
return (input) => {
if (input >= 1073741824) {
input = Math.round((input / 1073741824) * 10) / 10 + 'GB';
} else {
if (input >= 1048576) {
input = Math.round((input / 1048576) * 10) / 10 + 'MB';
} else {
if (input >= 1024) {
input = Math.round((input / 1024) * 10) / 10 + 'KB';
} else {
input = Math.round(input) + 'B';
}
}
return Math.round((input / 1073741824) * 10) / 10 + 'GB';
}
return input;
if (input >= 1048576) {
return Math.round((input / 1048576) * 10) / 10 + 'MB';
}
if (input >= 1024) {
return Math.round((input / 1024) * 10) / 10 + 'KB';
}
return Math.round(input) + 'B';
};
}
export function direct() {
return function(file) {
if(file.name) {
return (file) => {
if (file.name) {
if (file.direct && file.name.split('.').pop().toLowerCase() === 'psd') {
return file.direct['970x'].replace('/970/', '/').slice(0, -4);
} else if (file.direct && file.direct['970x']) {
return file.direct['970x'].replace('/970/', '/');
} else {
return file.href.replace('hostr.co/', 'hostr.co/file/') + '/' + file.name;
}
if (file.direct && file.direct['970x']) {
return file.direct['970x'].replace('/970/', '/');
}
return file.href.replace('hostr.co/', 'hostr.co/file/') + '/' + file.name;
}
};
}

View file

@ -1,72 +1,92 @@
export class FileService {
constructor($resource, $cacheFactory) {
var cache = $cacheFactory('files-cache');
return $resource(window.settings.apiURL + '/file/:id', {id: '@id'}, {
query: {method: 'GET', isArray: true, cache: cache,
params: {perpage: 0, all: true}
constructor($resource, $cacheFactory) {
const cache = $cacheFactory('files-cache');
return $resource(window.settings.apiURL + '/file/:id', {
id: '@id',
}, {
query: {
method: 'GET',
isArray: true,
cache: cache,
params: {
perpage: 0,
all: true,
},
},
delete: {
method: 'DELETE',
isArray: true,
cache: cache,
},
delete: {method: 'DELETE', isArray: true, cache: cache}
});
}
}
static factory($resource, $cacheFactory) {
static factory($resource, $cacheFactory) {
return new FileService($resource, $cacheFactory);
}
}
export class UserService {
constructor($resource) {
return $resource(window.settings.apiURL + '/user');
}
constructor($resource) {
return $resource(window.settings.apiURL + '/user');
}
static factory($resource) {
static factory($resource) {
return new UserService($resource);
}
}
export class EventService {
constructor($rootScope, ReconnectingWebSocket) {
if (window.user && WebSocket) {
let ws = new ReconnectingWebSocket('wss' + window.settings.apiURL.replace('https', '').replace('http', '') + '/user');
ws.onmessage = function (msg) {
var evt = JSON.parse(msg.data);
constructor($rootScope, ReconnectingWebSocket) {
if (window.user && WebSocket) {
const ws = new ReconnectingWebSocket('wss' + window.settings.apiURL.replace('https', '').replace('http', '') + '/user');
ws.onmessage = (msg) => {
const evt = JSON.parse(msg.data);
$rootScope.$broadcast(evt.type, evt.data);
};
ws.onopen = function() {
ws.send(JSON.stringify({authorization: window.user.token}));
ws.onopen = () => {
ws.send(JSON.stringify({
authorization: window.user.token,
}));
};
}
return true;
}
}
static factory($rootScope, ReconnectingWebSocket) {
return new EventService($rootScope, ReconnectingWebSocket);
}
static factory($rootScope, ReconnectingWebSocket) {
return new EventService($rootScope, ReconnectingWebSocket);
}
}
export class TransactionService {
constructor ($resource, $cacheFactory) {
var cache = $cacheFactory('transaction-cache');
return $resource(window.settings.apiURL + '/user/transaction/:id', {id: '@id'}, {
query: {method: 'GET', isArray: true, cache: cache}
constructor($resource, $cacheFactory) {
const cache = $cacheFactory('transaction-cache');
return $resource(window.settings.apiURL + '/user/transaction/:id', {
id: '@id',
}, {
query: {
method: 'GET',
isArray: true,
cache: cache,
},
});
}
static factory($resource, $cacheFactory) {
static factory($resource, $cacheFactory) {
return new TransactionService($resource, $cacheFactory);
}
}
export class SettingService {
constructor ($http) {
var service = {};
service.update = function(data) {
constructor($http) {
const service = {};
service.update = (data) => {
return $http.post(window.settings.apiURL + '/user/settings', data);
};
return service;
}
static factory($http) {
static factory($http) {
return new SettingService($http);
}
}

View file

@ -1,39 +1,35 @@
import fs from 'fs';
import path from 'path';
import mime from 'mime-types';
import hostrFileStream from '../../lib/hostr-file-stream';
import { formatFile } from '../../lib/format';
import debugname from 'debug';
const debug = debugname('hostr-web:file');
const storePath = process.env.STORE_PATH || path.join(process.env.HOME, '.hostr', 'uploads');
const userAgentCheck = function(userAgent) {
if (!userAgent){
function userAgentCheck(userAgent) {
if (!userAgent) {
return false;
}
return userAgent.match(/^(wget|curl|vagrant)/i);
};
}
const hotlinkCheck = function(file, userAgent, referrer) {
return !userAgentCheck(userAgent) && !file.width && (!referrer || !(referrer.match(/^https:\/\/hostr.co/) || referrer.match(/^http:\/\/localhost:4040/)))
};
function hotlinkCheck(file, userAgent, referrer) {
return !userAgentCheck(userAgent) && !file.width && (!referrer || !(referrer.match(/^https:\/\/hostr.co/) || referrer.match(/^http:\/\/localhost:4040/)));
}
export function* get() {
const file = yield this.db.Files.findOne({_id: this.params.id, 'file_name': this.params.name, 'status': 'active'});
this.assert(file, 404);
if (hotlinkCheck(file, this.headers['user-agent'], this.headers['referer'])) {
if (hotlinkCheck(file, this.headers['user-agent'], this.headers.referer)) {
return this.redirect('/' + file._id);
}
if (!file.width && this.request.query.warning != 'on') {
if (!file.width && this.request.query.warning !== 'on') {
return this.redirect('/' + file._id);
}
if (file.malware) {
let alert = this.request.query.alert;
const alert = this.request.query.alert;
if (!alert || !alert.match(/i want to download malware/i)) {
return this.redirect('/' + file._id);
}
@ -70,9 +66,9 @@ export function* get() {
if (!this.params.size || (this.params.size && this.params.size > 150)) {
this.db.Files.updateOne(
{_id: file._id},
{'$set': {'last_accessed': Math.ceil(Date.now()/1000)}, '$inc': {downloads: 1}},
{w:0}
{'_id': file._id},
{'$set': {'last_accessed': Math.ceil(Date.now() / 1000)}, '$inc': {downloads: 1}},
{'w': 0}
);
}
@ -86,7 +82,7 @@ export function* resized() {
export function* landing() {
const file = yield this.db.Files.findOne({_id: this.params.id, status: 'active'});
this.assert(file, 404);
if(userAgentCheck(this.headers['user-agent'])) {
if (userAgentCheck(this.headers['user-agent'])) {
this.params.name = file.file_name;
return yield get.call(this);
}

View file

@ -32,24 +32,24 @@ export function* staticPage(next) {
this.session.user.token = token;
yield this.render('index', {user: this.session.user});
} else {
switch(this.originalUrl) {
case '/terms':
yield this.render('terms');
break;
case '/privacy':
yield this.render('privacy');
break;
case '/pricing':
yield this.render('pricing');
break;
case '/apps':
yield this.render('apps');
break;
case '/stats':
yield this.render('index', {user: {}});
break;
default:
yield next;
switch (this.originalUrl) {
case '/terms':
yield this.render('terms');
break;
case '/privacy':
yield this.render('privacy');
break;
case '/pricing':
yield this.render('pricing');
break;
case '/apps':
yield this.render('apps');
break;
case '/stats':
yield this.render('index', {user: {}});
break;
default:
yield next;
}
}
}

View file

@ -17,7 +17,7 @@ export function* create() {
const createCustomer = {
card: stripeToken.id,
plan: 'usd_monthly',
email: this.session.email
email: this.session.email,
};
const customer = yield stripe.customers.create(createCustomer);
@ -32,7 +32,7 @@ export function* create() {
'user_id': this.session.user.id,
amount: customer.subscription.plan.amount,
desc: customer.subscription.plan.name,
date: new Date(customer.subscription.plan.created * 1000)
date: new Date(customer.subscription.plan.created * 1000),
};
yield Transactions.insertOne(transaction);
@ -40,8 +40,8 @@ export function* create() {
this.session.user.plan = 'Pro';
this.body = {status: 'active'};
let html = yield render('email/inlined/pro');
let text = `Hey, thanks for upgrading to Hostr Pro!
const html = yield render('email/inlined/pro');
const text = `Hey, thanks for upgrading to Hostr Pro!
You've signed up for Hostr Pro Monthly at $6/Month.
@ -56,11 +56,11 @@ export function* create() {
'from_name': fromName,
to: [{
email: this.session.user.email,
type: 'to'
type: 'to',
}],
'tags': [
'pro-upgrade'
]
'pro-upgrade',
],
}});
}

View file

@ -10,16 +10,15 @@ export function* signin() {
this.statsd.incr('auth.attempt', 1);
this.assertCSRF(this.request.body);
const user = yield authenticate.call(this, this.request.body.email, this.request.body.password);
if(!user) {
if (!user) {
this.statsd.incr('auth.failure', 1);
return yield this.render('signin', {error: 'Invalid login details', csrf: this.csrf});
} else if (user.activationCode) {
return yield this.render('signin', {error: 'Your account hasn\'t been activated yet. Check your for an activation email.', csrf: this.csrf});
} else {
this.statsd.incr('auth.success', 1);
yield setupSession.call(this, user);
this.redirect('/');
}
this.statsd.incr('auth.success', 1);
yield setupSession.call(this, user);
this.redirect('/');
}
@ -60,7 +59,7 @@ export function* forgot() {
}
this.assertCSRF(this.request.body);
const tokenUser = yield validateResetToken.call(this, token);
var userId = tokenUser._id;
const userId = tokenUser._id;
yield updatePassword.call(this, userId, this.request.body.password);
yield Reset.deleteOne({_id: userId});
const user = yield Users.findOne({_id: userId});
@ -72,13 +71,12 @@ export function* forgot() {
if (!tokenUser) {
this.statsd.incr('auth.reset.fail', 1);
return yield this.render('forgot', {error: 'Invalid password reset token. It might be expired, or has already been used.', token: null, csrf: this.csrf});
} else {
return yield this.render('forgot', {token: token, csrf: this.csrf});
}
return yield this.render('forgot', {token: token, csrf: this.csrf});
} else if (this.request.body.email) {
this.assertCSRF(this.request.body);
try {
var email = this.request.body.email;
const email = this.request.body.email;
yield sendResetToken.call(this, email);
this.statsd.incr('auth.reset.request', 1);
return yield this.render('forgot', {message: 'We\'ve sent an email with a link to reset your password. Be sure to check your spam folder if you it doesn\'t appear within a few minutes', token: null, csrf: this.csrf});