Bladeren bron

Work on stuff

pull/9/head
Jack 6 jaren geleden
bovenliggende
commit
f1e9e7e78b
25 gewijzigde bestanden met toevoegingen van 296 en 258 verwijderingen
  1. +22
    -0
      app/models/Key.js
  2. +0
    -30
      app/models/Token.js
  3. +3
    -33
      app/models/User.js
  4. +13
    -22
      app/routes.js
  5. +44
    -70
      app/routes/auth.js
  6. +67
    -0
      app/routes/keys.js
  7. +5
    -12
      app/routes/upload.js
  8. +3
    -25
      config/passport.js
  9. +5
    -3
      package.json
  10. +40
    -0
      public/css/panel.css
  11. BIN
      public/img/edge.mp4
  12. BIN
      public/img/flower.png
  13. +20
    -0
      public/js/services/ApiSvc.js
  14. +12
    -40
      public/js/services/AuthSvc.js
  15. +8
    -0
      public/js/shimapan-panel/controllers/ApiCtrl.js
  16. +7
    -5
      public/js/shimapan-panel/controllers/NavCtrl.js
  17. +1
    -1
      public/js/shimapan-panel/routes.js
  18. +1
    -1
      public/js/shimapan-panel/shimapan-panel.js
  19. +0
    -3
      public/js/shimapan/components/UploadComp.js
  20. +11
    -1
      public/views/shimapan-panel/panel-api.html
  21. +1
    -0
      public/views/shimapan-panel/panel-dash.html
  22. +0
    -2
      public/views/shimapan-panel/panel-home.html
  23. +32
    -3
      server.js
  24. +0
    -1
      test/api.js
  25. +1
    -6
      test/testUtil.js

+ 22
- 0
app/models/Key.js Bestand weergeven

@@ -0,0 +1,22 @@
var mongoose = require('mongoose');

var KeySchema = mongoose.Schema({
key: String,
identifier: {
type: String,
required: true
},
scope: [String],
uploadCount: {
type: Number,
default: 0
},
uploadSize: {
type: Number,
default: 0
},
username: String,
date: Date
});

module.exports = mongoose.model('Key', KeySchema);

+ 0
- 30
app/models/Token.js Bestand weergeven

@@ -1,30 +0,0 @@
var fs = require('fs');
var path = require('path');
var mongoose = require('mongoose');
var jwt = require('jsonwebtoken');
var jwtsign = require('jwt-sign');

var TokenSchema = mongoose.Schema({
scope: [String],
issuer: String,
issued: Date,
exp: Date
});

TokenSchema.methods.genJwt = function(expiry) {
var exp = new Date();
exp.setDate(exp.getDate() + expiry);

var payload = {
_id: this._id,
username: this.username,
scope: this.scope,
exp: parseInt(exp.getTime() / 1000)
};

var key = fs.readFilySync(path.join(__dirname, '../../jwt.pem'), 'utf8');

return jwt.sign(payload, key);
};

module.exports = mongoose.model('Token', TokenSchema);

+ 3
- 33
app/models/User.js Bestand weergeven

@@ -1,9 +1,5 @@
var fs = require('fs');
var path = require('path');
var mongoose = require('mongoose');
var crypto = require('crypto');
var jwt = require('jsonwebtoken');
var jwtsign = require('jwt-sign');
var passportLocalMongoose = require('passport-local-mongoose');

var UserSchema = mongoose.Schema({
username: {
@@ -11,6 +7,7 @@ var UserSchema = mongoose.Schema({
unique: true,
required: true
},
scope: [String],
uploadCount: {
type: Number,
default: 0
@@ -19,36 +16,9 @@ var UserSchema = mongoose.Schema({
type: Number,
default: 0
},
scope: [String],
hash: String,
salt: String,
date: Date
});

UserSchema.methods.setPassword = function(password) {
this.salt = crypto.randomBytes(16).toString('hex');
this.hash = crypto.pbkdf2Sync(password, this.salt, 1000, 64, 'sha256').toString('hex');
};

UserSchema.methods.validatePassword = function(password) {
var hash = crypto.pbkdf2Sync(password, this.salt, 1000, 64, 'sha256').toString('hex');
return this.hash === hash;
};

UserSchema.methods.genJwt = function() {
var expiry = new Date();
expiry.setDate(expiry.getDate() + 7);

var payload = {
_id: this._id,
username: this.username,
scope: this.scope,
exp: parseInt(expiry.getTime() / 1000)
};

var key = fs.readFileSync(path.join(__dirname, '../../jwt.pem'), 'utf8');

return jwt.sign(payload, key);
};
UserSchema.plugin(passportLocalMongoose);

module.exports = mongoose.model('User', UserSchema);

+ 13
- 22
app/routes.js Bestand weergeven

@@ -5,43 +5,34 @@ var view = require('./routes/view.js');
var auth = require('./routes/auth.js');
var register = require('./routes/register.js');
var login = require('./routes/login.js');
var panel = require('./routes/panel');
var panel = require('./routes/panel.js');
var keys = require('./routes/keys.js');

var fs = require('fs');
var path = require('path');
var jwt = require('express-jwt');
var jwtauth = jwt({
secret: fs.readFileSync(path.join(__dirname, '../jwt.pem'), 'utf8'),
userProperty: 'payload',
getToken: function(req) {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
// First check Authorization header
return req.headers.authorization.split(' ')[1];
} else if (req.cookies && req.cookies['shimapan-token']) {
// Get from cookies as fallback
return req.cookies['shimapan-token'];
}

// no token received
return null;
}
});
var requireLogin = function(req, res, next) {
if (!req.session.passport.user)
res.redirect('/login');
else
next();
};

module.exports = function(app) {
app.use('/', index);
app.use('/home', jwtauth, home);
app.use('/home', requireLogin, home);
app.use('/v', view);
app.use('/api/upload', jwtauth, upload);
app.use('/api/upload', upload);
app.use('/api/auth', auth);
app.use('/api/keys', requireLogin, keys);
app.use('/register', register);
app.use('/login', login);
app.use('/panel', jwtauth, panel);
app.use('/panel*', jwtauth, panel);
app.use('/panel', requireLogin, panel);
app.use('/panel*', requireLogin, panel);

app.use(function(err, req, res, next) {
if (err.name === 'UnauthorizedError') {
res.status(401);
res.redirect('/login');
res.json({"message": err.name + ": " + err.message});
}
})

+ 44
- 70
app/routes/auth.js Bestand weergeven

@@ -3,25 +3,12 @@ var path = require('path');

var express = require('express');
var router = express.Router();
var async = require('async');

var User = require('../models/User.js');
var Invite = require('../models/Invite.js');

var passport = require('passport');

var striptags = require('striptags');

function checkUsername(username, callback) {
if (username.length > 30) return callback(null, false);
if (striptags(username) !== username) return callback(null, false);

User.find({username: username}).limit(1).count(function (err, count) {
if (err) return callback(err);
(count === 0) ? callback(null, true) : callback(null, false);
});
}

function checkInvite(code, callback) {
Invite.findOne({code: code}, function (err, invite) {
if (err) return callback(err);
@@ -33,75 +20,62 @@ function checkInvite(code, callback) {
}

function useInvite(code, username) {
Invite.updateOne({code: code}, {recipient: username, used: new Date()}, function (err, res) {
Invite.updateOne({code: code}, {recipient: username, used: new Date()}, function (err) {
if (err) throw err;
});
}

router.post('/register', function (req, res) {
// Validate the parameters
async.parallel({
userCheck: function (callback) {
checkUsername(req.body.username, function (err, valid) {
callback(err, valid);
});
},
inviteCheck: function (callback) {
checkInvite(req.body.invite, function (err, valid, invite) {
callback(err, {valid: valid, invite: invite});
});
}
}, function (err, result) {
if (!result.userCheck) {
res.status(401).json({'message': 'Invalid username.'});
} else if (!result.inviteCheck.valid) {
res.status(401).json({'message': 'Invalid invite code.'});
} else {
useInvite(req.body.invite, req.body.username);
var user = new User();
user.username = req.body.username;
user.scope = result.inviteCheck.invite.scope;
user.date = new Date();
user.setPassword(req.body.password);

user.save(function (err) {
if (err) {
res.status(500).json({'message': 'Internal server error.'});
} else {
res.status(200)
.cookie('shimapan-token', user.genJwt(), {
expires: new Date(Date.now() + 604800000),
httpOnly: true
})
.json({'token': user.genJwt()});
router.post('/register', function (req, res, next) {
// Validate the invite code, then hand off to passport
checkInvite(req.body.invite, function (err, valid, invite) {
if (valid) {
User.register(
new User({username: req.body.username, scope: invite.scope, date: Date.now()}),
req.body.password,
function (err) {
if (err) return res.status(403).json({'message': err.message});
passport.authenticate('local')(req, res, function () {
req.session.save(function(err) {
if (err) return next(err);
useInvite(req.body.invite, req.body.username);
res.status(200).json({'message': 'Registered.'});
});
});
}
});
);
} else {
res.status(401).json({'message': 'Invalid invite code.'});
}
});
});

router.post('/login', function (req, res) {
passport.authenticate('local', function (err, user, info) {
if (err) {
res.status(500).json(err);
} else if (user) {
res.status(200)
.cookie('shimapan-token', user.genJwt(), {
expires: new Date(Date.now() + 604800000),
httpOnly: true
})
.json({'token': user.genJwt()});
} else {
res.status(401).json(info);
}

})(req, res);
router.post('/login', function (req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) return next(err);
if (!user) return res.status(401).json({'message': info});
req.logIn(user, function(err) {
if (err) return next(err);
res.status(200).json({'message': 'Logged in.'});
});
})(req, res, next);
});

router.get('/logout', function(req, res) {
res.clearCookie('shimapan-token');
res.status(200).json({'message': 'Successfully logged out.'});
router.get('/logout', function (req, res) {
req.logout();
res.status(200).json({'message': 'Logged out.'});
});

router.get('/session', function(req, res) {
if (req.session.passport.user) {
User.findOne({username: req.session.passport.user}, function(err, user) {
res.status(200).json({
user: user.username,
scope: user.scope
});
});
} else {
res.status(401).json({'message': 'Unauthorized.'});
}
});

module.exports = router;

+ 67
- 0
app/routes/keys.js Bestand weergeven

@@ -0,0 +1,67 @@
var express = require('express');
var router = express.Router();
var crypto = require('crypto');

var Key = require('../models/Key.js');

router.post('/create', function (req, res) {
if (!req.body.identifier || !req.body.scope) {
res.status(400).json({'message': 'Bad request.'});
return;
}

Key.count({'username': req.session.passport.user}, function (err, count) {
if (count >= 10) {
res.status(403).json({'message': 'Key limit reached.'});
return;
}

var scope;
try {
scope = JSON.parse(req.body.scope);
} catch (e) {
res.status(400).json({'message': e.name + ': ' + e.message});
return;
}

var id = req.sanitize(req.body.identifier);
if (id.length === 0) id = "err";

var entry = {
key: crypto.randomBytes(32).toString('hex'),
identifier: id,
scope: scope,
username: req.session.passport.user,
date: Date.now()
};

Key.create(entry, function (err) {
if (err) {
throw err;
} else {
res.status(200).json({
key: entry.key,
identifier: entry.identifier,
scope: entry.scope
});
}
})
})
});

router.get('/get', function (req, res, next) {
var query = {username: req.session.passport.user};

if (req.body.identifier)
query.identifier = req.body.identifier;

Key.find(query, function (err, keys) {
if (err) {
next(err);
} else {
res.status(200).json(keys);
}
})
});

module.exports = router;

+ 5
- 12
app/routes/upload.js Bestand weergeven

@@ -14,11 +14,9 @@ function fileNameExists(name) {
});
}

function updateStats(user, size) {
User.updateOne({username: user}, { $inc: { uploadCount: 1, uploadSize: size } }, function(err, res) {
if (err) {
throw err;
}
function updateUserStats(user, size) {
User.updateOne({username: user}, {$inc: {uploadCount: 1, uploadSize: size}}, function (err, res) {
if (err) throw err;
});
}

@@ -33,22 +31,17 @@ function genFileName() {
}

router.post('/', dest.single('file'), function (req, res) {
if (req.payload.scope.indexOf('file.upload') === -1) {
res.status(403).json({'message': 'Permission error.'});
return;
}

// Size must be below 128 Megabytes (1024*1024*128 Bytes)
if (req.file.size >= 134217728) {
res.status(413).json({'message': 'File too large.'});
return;
}

updateStats(req.payload.username, req.file.size);
updateUserStats(req.session.passport.user, req.file.size);

var entry = {
name: genFileName(),
uploader: req.payload.username,
uploader: req.session.passport.user,
created: Date.now(),
file: req.file
};


+ 3
- 25
config/passport.js Bestand weergeven

@@ -1,29 +1,7 @@
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;

var mongoose = require('mongoose');
var User = require('../app/models/User.js');

passport.use(new LocalStrategy({
usernameField: 'username'
},
function(username, password, done) {
User.findOne({username: username}, function(err, user) {
if (err) return done(err);

if (!user) {
return done(null, false, {
message: 'Invalid username.'
});
}

if (!user.validatePassword(password)) {
return done(null, false, {
message: 'Invalid password.'
});
}
passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

return done(null, user);
});
}
));

+ 5
- 3
package.json Bestand weergeven

@@ -7,11 +7,12 @@
"async": "^2.5.0",
"body-parser": "^1.18.2",
"config": "^1.26.2",
"connect-mongo": "^2.0.0",
"cookie-parser": "^1.4.3",
"express": "^4.16.2",
"express-jwt": "^5.3.0",
"jsonwebtoken": "^8.1.0",
"jwt-sign": "^0.1.0",
"express-sanitizer": "^1.0.2",
"express-session": "^1.15.6",
"helmet": "^3.9.0",
"method-override": "latest",
"mongoose": "^4.12.1",
"morgan": "^1.9.0",
@@ -19,6 +20,7 @@
"ng-file-upload": "^12.2.13",
"passport": "^0.4.0",
"passport-local": "^1.0.0",
"passport-local-mongoose": "^4.2.1",
"striptags": "^3.1.0"
},
"description": "A simple file sharing website.",


+ 40
- 0
public/css/panel.css Bestand weergeven

@@ -98,3 +98,43 @@ body {
box-shadow: inset 5px 0 0 #2A9FD6, inset 6px 0 0 #222;
background: #444;
}

.inner {
display: flex;
flex-direction: column;
}

.keys {
display: flex;
flex-direction: row;
}

.key {
background: #555;
border: 3px solid #2a9fd6;
border-radius: 5px;
box-shadow: 5px 5px 10px #000;
margin: 10px;
width: 300px;
height: 100px;
}

.add-key {
cursor: pointer;
display: flex;
justify-content: flex-start;
flex-direction: row;
}

.add-key i {
font-size: 48px;
margin: auto 0 auto 20px;
}

.add-key span {
font-size: 36px;
vertical-align: center;
margin: auto;
-moz-user-select: none;
user-select: none;
}

BIN
public/img/edge.mp4 Bestand weergeven


BIN
public/img/flower.png Bestand weergeven

Before After
Width: 700  |  Height: 700  |  Size: 249KB

+ 20
- 0
public/js/services/ApiSvc.js Bestand weergeven

@@ -0,0 +1,20 @@
angular.module('ApiSvc', []).service('ApiService', ['$http', '$window', function ($http, $window) {
this.getKey = function (identifier, cb) {
$http({
method: 'GET',
url: '/api/keys/get',
params: {identifier: identifier}
}).then(function (res) {
cb(res.data);
});
};

this.getAll = function (cb) {
$http({
method: 'GET',
url: '/api/keys/get'
}).then(function (res) {
cb(res.data);
});
};
}]);

+ 12
- 40
public/js/services/AuthSvc.js Bestand weergeven

@@ -1,28 +1,4 @@
angular.module('AuthSvc', []).service('AuthService', ['$http', '$window', function($http, $window) {
function decodeToken(token) {
if (token) {
var payload = token.split('.')[1];
payload = $window.atob(payload);
payload = JSON.parse(payload);
return payload;
} else {
return {};
}
}

function saveToken(token) {
$window.localStorage['shimapan-token'] = token;
}

function getToken() {
return $window.localStorage['shimapan-token'];
}

this.getAuthHeader = function() {
return 'Bearer ' + getToken();
};


this.login = function(user) {
return $http({
method: 'POST',
@@ -36,23 +12,19 @@ angular.module('AuthSvc', []).service('AuthService', ['$http', '$window', functi
},
data: user
}).then(function(res) {
saveToken(res.data.token);
if (res.status === 401) return false;
$window.location.href = '/home';
})
};

this.logout = function() {
$window.localStorage.removeItem('shimapan-token');
$http({
method: 'GET',
url: '/api/auth/logout'
}).then(function(res) {
}).then(function() {
$window.location.href = '/';
});
};
this.isLoggedIn = function() {
var payload = decodeToken(getToken());
return payload.exp > Date.now() / 1000;
};

this.register = function(user) {
return $http({
@@ -67,18 +39,18 @@ angular.module('AuthSvc', []).service('AuthService', ['$http', '$window', functi
},
data: user
}).then(function(res) {
saveToken(res.data.token);
if (res.status === 401) return false;
$window.location.href = '/home';
});
};

this.currentUser = function() {
var payload = decodeToken(getToken());
return payload.username;
};
this.currentScope = function() {
var payload = decodeToken(getToken());
return payload.scope;
this.currentUser = function(cb) {
return $http({
method: 'GET',
url: '/api/auth/session',
headers: {'Content-Type': 'application/json'}
}).then(function(res) {
cb(res.data);
});
}
}]);

+ 8
- 0
public/js/shimapan-panel/controllers/ApiCtrl.js Bestand weergeven

@@ -0,0 +1,8 @@
angular.module('ApiCtrl', ['ApiSvc', 'AuthSvc']).controller('ApiController', ['$scope', 'ApiService', 'AuthService', function($scope, ApiService, AuthService) {
$scope.getKeys = function() {
ApiService.getAll(function(keys) {
$scope.keys = keys;
});
console.log($scope.keys);
};
}]);

+ 7
- 5
public/js/shimapan-panel/controllers/NavCtrl.js Bestand weergeven

@@ -1,12 +1,14 @@
angular.module('NavCtrl', ['AuthSvc']).controller('NavController', ['$scope', '$window', 'AuthService', function($scope, $window, AuthService) {
$scope.isLoggedIn = AuthService.isLoggedIn();
$scope.currentUser = AuthService.currentUser();
$scope.currentScope = AuthService.currentScope();
$scope.user = {};
AuthService.currentUser(function(user) {
$scope.user = user;
});

$scope.logout = AuthService.logout;

$scope.hasPermission = function(permission) {
if (!$scope.currentScope) return false;
return $scope.currentScope.indexOf(permission) !== -1;
if (!$scope.user.scope) return false;
return $scope.user.scope.indexOf(permission) !== -1;
};

}]);

+ 1
- 1
public/js/shimapan-panel/routes.js Bestand weergeven

@@ -6,7 +6,7 @@ angular.module('PanelRoutes', ['ui.router']).config(['$stateProvider', '$urlRout
$stateProvider
.state('dashboard', {
url: '/panel',
templateUrl: '/views/shimapan-panel/panel-home.html'
templateUrl: '/views/shimapan-panel/panel-dash.html'
}).state('search', {
url: '/panel/search',
templateUrl: '/views/shimapan-panel/panel-search.html'


+ 1
- 1
public/js/shimapan-panel/shimapan-panel.js Bestand weergeven

@@ -1,4 +1,4 @@
var app = angular.module('shimapan-panel', ['ui.router', 'NavCtrl', 'PanelRoutes']);
var app = angular.module('shimapan-panel', ['ui.router', 'AuthSvc', 'ApiSvc', 'ApiCtrl', 'NavCtrl', 'PanelRoutes']);

app.run(['$rootScope', '$state', '$stateParams', function($rootScope, $state, $stateParams) {
$rootScope.$state = $state;


+ 0
- 3
public/js/shimapan/components/UploadComp.js Bestand weergeven

@@ -16,9 +16,6 @@ angular.module('UploadComp', ['ngFileUpload', 'AuthSvc']).component('uploadCompo
file.upload = Upload.upload({
url: '/api/upload',
method: 'POST',
headers: {
'Authorization': AuthService.getAuthHeader()
},
file: file
});



+ 11
- 1
public/views/shimapan-panel/panel-api.html Bestand weergeven

@@ -1 +1,11 @@
<h1>Panel api hurr durr</h1>
<div class="inner">
<p ng-hide="keys">Loading...</p>
<div class="keys" ng-controller="ApiController" ng-init="getKeys()">
<div class="key" ng-repeat="key in keys">
</div>
<div class="key add-key">
<i class="fa fa-plus"></i>
<span>Create</span>
</div>
</div>
</div>

+ 1
- 0
public/views/shimapan-panel/panel-dash.html Bestand weergeven

@@ -0,0 +1 @@
<h1>Dashboard</h1>

+ 0
- 2
public/views/shimapan-panel/panel-home.html Bestand weergeven

@@ -1,2 +0,0 @@
<h1>This is yer home</h1>
<p>This is a pargragraph</p>

+ 32
- 3
server.js Bestand weergeven

@@ -5,6 +5,9 @@ var mongoose = require('mongoose');
var morgan = require('morgan');
var passport = require('passport');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var sanitizer = require('express-sanitizer');
var helmet = require('helmet');

var app = express();

@@ -19,20 +22,46 @@ var db = mongoose.connection;
db.on('error', function(err) {
if (err) console.log('MongoDB Connection Error: ', err);
});
var MongoStore = require('connect-mongo')(session);
var mongoStore = new MongoStore({
url: config.dbHost
});

require('./config/passport.js');

app.use(helmet());
app.set('trust proxy', 1);
app.use(session({
secret: 'secret',
name: 'session.id',
resave: false,
saveUninitialized: false,
store: mongoStore,
cookie: {
//secure: true,
httpOnly: true,
//domain: 'shimapan.rocks',
maxAge: 1000 * 60 * 60
}
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.json({ type: 'application/json' }));
app.use(bodyParser.json({ type: 'application/*+json' }))
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.text());
app.use(sanitizer());
app.use(methodOverride('X-HTTP-Method-Override'));
app.use(passport.initialize());

// Set /public to document root

//app.use(favicon(__dirname + '/public/img/favicon.ico'));
app.use(express.static(__dirname + '/public'));


require('./app/routes')(app);
require('./config/passport.js');


// Start app
var port = process.env.PORT || 8080;


+ 0
- 1
test/api.js Bestand weergeven

@@ -6,7 +6,6 @@ var mongoose = require('mongoose');
var User = require('../app/models/User.js');
var Invite = require('../app/models/Invite.js');
var Upload = require('../app/models/Upload.js');
var Token = require('../app/models/Token.js');

var chai = require('chai');
var should = chai.should();


+ 1
- 6
test/testUtil.js Bestand weergeven

@@ -6,7 +6,6 @@ var mongoose = require('mongoose');
var User = require('../app/models/User.js');
var Invite = require('../app/models/Invite.js');
var Upload = require('../app/models/Upload.js');
var Token = require('../app/models/Token.js');

var chai = require('chai');
var http = require('chai-http');
@@ -24,7 +23,7 @@ chai.use(http);
var resetDatabase = function(callback) {
db.once('open', function() {
async.each([
User, Invite, Upload, Token
User, Invite, Upload,
], function(schema, cb) {
schema.remove({}, function(err) {
cb(err);
@@ -73,8 +72,6 @@ var register = function(user, cb) {
var verifySuccessfulRegister = function(user, done) {
register(user, function (err, res) {
res.should.have.status(200);
res.body.should.be.a('object');
res.body.should.have.property('token');
done();
});
};
@@ -111,8 +108,6 @@ var login = function(user, cb) {
var verifySuccessfulLogin = function(user, done) {
login(user, function (err, res) {
res.should.have.status(200);
res.body.should.be.a('object');
res.body.should.have.property('token');
done();
});
};


Laden…
Annuleren
Opslaan