From 69b0a27cbbd69ca019eb7db5f917b1dd06dc82cd Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 1 Jul 2016 16:03:53 +0200 Subject: [PATCH] OAuth/User models refractoring -> use mongoose api --- server.js | 16 +-- server/controllers/api/v1/pods.js | 6 +- server/controllers/api/v1/users.js | 9 +- server/controllers/api/v1/videos.js | 6 +- server/initializers/checker.js | 8 +- server/initializers/database.js | 3 + server/initializers/installer.js | 27 +++-- server/lib/oauth-model.js | 70 ++++++++++++ server/middlewares/index.js | 4 +- server/middlewares/{oauth2.js => oauth.js} | 6 +- server/models/oauth-client.js | 33 ++++++ server/models/oauth-token.js | 34 ++++++ server/models/user.js | 28 +++++ server/models/users.js | 123 --------------------- 14 files changed, 217 insertions(+), 156 deletions(-) create mode 100644 server/lib/oauth-model.js rename server/middlewares/{oauth2.js => oauth.js} (89%) create mode 100644 server/models/oauth-client.js create mode 100644 server/models/oauth-token.js create mode 100644 server/models/user.js delete mode 100644 server/models/users.js diff --git a/server.js b/server.js index 9322bca19..e0284b080 100644 --- a/server.js +++ b/server.js @@ -13,14 +13,6 @@ const WebSocketServer = require('ws').Server // Create our main app const app = express() -// ----------- Checker ----------- -const checker = require('./server/initializers/checker') - -const miss = checker.checkConfig() -if (miss.length !== 0) { - throw new Error('Miss some configurations keys : ' + miss) -} - // ----------- Database ----------- const config = require('config') const constants = require('./server/initializers/constants') @@ -29,6 +21,14 @@ const logger = require('./server/helpers/logger') database.connect() +// ----------- Checker ----------- +const checker = require('./server/initializers/checker') + +const miss = checker.checkConfig() +if (miss.length !== 0) { + throw new Error('Miss some configurations keys : ' + miss) +} + // ----------- PeerTube modules ----------- const customValidators = require('./server/helpers/customValidators') const installer = require('./server/initializers/installer') diff --git a/server/controllers/api/v1/pods.js b/server/controllers/api/v1/pods.js index feb6bd958..9ce8120b2 100644 --- a/server/controllers/api/v1/pods.js +++ b/server/controllers/api/v1/pods.js @@ -7,7 +7,7 @@ const mongoose = require('mongoose') const logger = require('../../../helpers/logger') const friends = require('../../../lib/friends') const middlewares = require('../../../middlewares') -const oAuth2 = middlewares.oauth2 +const oAuth = middlewares.oauth const reqValidator = middlewares.reqValidators.pods const signatureValidator = middlewares.reqValidators.remote.signature @@ -17,8 +17,8 @@ const Video = mongoose.model('Video') router.get('/', listPodsUrl) router.post('/', reqValidator.podsAdd, addPods) -router.get('/makefriends', oAuth2.authenticate, reqValidator.makeFriends, makeFriends) -router.get('/quitfriends', oAuth2.authenticate, quitFriends) +router.get('/makefriends', oAuth.authenticate, reqValidator.makeFriends, makeFriends) +router.get('/quitfriends', oAuth.authenticate, quitFriends) // Post because this is a secured request router.post('/remove', signatureValidator, removePods) diff --git a/server/controllers/api/v1/users.js b/server/controllers/api/v1/users.js index 7ce0b9c6a..caa979567 100644 --- a/server/controllers/api/v1/users.js +++ b/server/controllers/api/v1/users.js @@ -1,15 +1,16 @@ 'use strict' const config = require('config') +const mongoose = require('mongoose') const express = require('express') -const oAuth2 = require('../../../middlewares').oauth2 +const oAuth = require('../../../middlewares').oauth -const Users = require('../../../models/users') +const Client = mongoose.model('OAuthClient') const router = express.Router() router.get('/client', getAngularClient) -router.post('/token', oAuth2.token, success) +router.post('/token', oAuth.token, success) // --------------------------------------------------------------------------- @@ -27,7 +28,7 @@ function getAngularClient (req, res, next) { if (req.get('host') !== headerHostShouldBe) return res.type('json').status(403).end() - Users.getFirstClient(function (err, client) { + Client.loadFirstClient(function (err, client) { if (err) return next(err) if (!client) return next(new Error('No client available.')) diff --git a/server/controllers/api/v1/videos.js b/server/controllers/api/v1/videos.js index d06ec8d08..ab115bc30 100644 --- a/server/controllers/api/v1/videos.js +++ b/server/controllers/api/v1/videos.js @@ -9,7 +9,7 @@ const multer = require('multer') const logger = require('../../../helpers/logger') const friends = require('../../../lib/friends') const middlewares = require('../../../middlewares') -const oAuth2 = middlewares.oauth2 +const oAuth = middlewares.oauth const pagination = middlewares.pagination const reqValidator = middlewares.reqValidators const reqValidatorPagination = reqValidator.pagination @@ -51,7 +51,7 @@ router.get('/', listVideos ) router.post('/', - oAuth2.authenticate, + oAuth.authenticate, reqFiles, reqValidatorVideos.videosAdd, addVideo @@ -61,7 +61,7 @@ router.get('/:id', getVideo ) router.delete('/:id', - oAuth2.authenticate, + oAuth.authenticate, reqValidatorVideos.videosRemove, removeVideo ) diff --git a/server/initializers/checker.js b/server/initializers/checker.js index 7a2b5b132..3831efb8d 100644 --- a/server/initializers/checker.js +++ b/server/initializers/checker.js @@ -1,8 +1,10 @@ 'use strict' const config = require('config') +const mongoose = require('mongoose') -const Users = require('../models/users') +const Client = mongoose.model('OAuthClient') +const User = mongoose.model('User') const checker = { checkConfig: checkConfig, @@ -29,7 +31,7 @@ function checkConfig () { } function clientsExist (callback) { - Users.getClients(function (err, clients) { + Client.list(function (err, clients) { if (err) return callback(err) return callback(null, clients.length !== 0) @@ -37,7 +39,7 @@ function clientsExist (callback) { } function usersExist (callback) { - Users.getUsers(function (err, users) { + User.list(function (err, users) { if (err) return callback(err) return callback(null, users.length !== 0) diff --git a/server/initializers/database.js b/server/initializers/database.js index e97531781..4a19bc230 100644 --- a/server/initializers/database.js +++ b/server/initializers/database.js @@ -6,6 +6,9 @@ const mongoose = require('mongoose') const logger = require('../helpers/logger') // Bootstrap models +require('../models/user') +require('../models/oauth-client') +require('../models/oauth-token') require('../models/pods') require('../models/video') // Request model needs Video model diff --git a/server/initializers/installer.js b/server/initializers/installer.js index 059fcd8d8..e0ae822cf 100644 --- a/server/initializers/installer.js +++ b/server/initializers/installer.js @@ -3,13 +3,16 @@ const async = require('async') const config = require('config') const mkdirp = require('mkdirp') +const mongoose = require('mongoose') const passwordGenerator = require('password-generator') const path = require('path') const checker = require('./checker') const logger = require('../helpers/logger') const peertubeCrypto = require('../helpers/peertubeCrypto') -const Users = require('../models/users') + +const Client = mongoose.model('OAuthClient') +const User = mongoose.model('User') const installer = { installApplication: installApplication @@ -60,11 +63,16 @@ function createOAuthClientIfNotExist (callback) { logger.info('Creating a default OAuth Client.') const secret = passwordGenerator(32, false) - Users.createClient(secret, [ 'password' ], function (err, id) { + const client = new Client({ + clientSecret: secret, + grants: [ 'password' ] + }) + + client.save(function (err, createdClient) { if (err) return callback(err) - logger.info('Client id: ' + id) - logger.info('Client secret: ' + secret) + logger.info('Client id: ' + createdClient._id) + logger.info('Client secret: ' + createdClient.clientSecret) return callback(null) }) @@ -94,11 +102,16 @@ function createOAuthUserIfNotExist (callback) { password = passwordGenerator(8, true) } - Users.createUser(username, password, function (err) { + const user = new User({ + username: username, + password: password + }) + + user.save(function (err, createdUser) { if (err) return callback(err) - logger.info('Username: ' + username) - logger.info('User password: ' + password) + logger.info('Username: ' + createdUser.username) + logger.info('User password: ' + createdUser.password) return callback(null) }) diff --git a/server/lib/oauth-model.js b/server/lib/oauth-model.js new file mode 100644 index 000000000..f4fd9805a --- /dev/null +++ b/server/lib/oauth-model.js @@ -0,0 +1,70 @@ +const mongoose = require('mongoose') + +const logger = require('../helpers/logger') + +const OAuthClient = mongoose.model('OAuthClient') +const OAuthToken = mongoose.model('OAuthToken') +const User = mongoose.model('User') + +// See https://github.com/oauthjs/node-oauth2-server/wiki/Model-specification for the model specifications +const OAuthModel = { + getAccessToken: getAccessToken, + getClient: getClient, + getRefreshToken: getRefreshToken, + getUser: getUser, + saveToken: saveToken +} + +// --------------------------------------------------------------------------- + +function getAccessToken (bearerToken) { + logger.debug('Getting access token (bearerToken: ' + bearerToken + ').') + + return OAuthToken.loadByTokenAndPopulateUser(bearerToken) +} + +function getClient (clientId, clientSecret) { + logger.debug('Getting Client (clientId: ' + clientId + ', clientSecret: ' + clientSecret + ').') + + // TODO req validator + const mongoId = new mongoose.mongo.ObjectID(clientId) + return OAuthClient.loadByIdAndSecret(mongoId, clientSecret) +} + +function getRefreshToken (refreshToken) { + logger.debug('Getting RefreshToken (refreshToken: ' + refreshToken + ').') + + return OAuthToken.loadByRefreshToken(refreshToken) +} + +function getUser (username, password) { + logger.debug('Getting User (username: ' + username + ', password: ' + password + ').') + + return User.loadByUsernameAndPassword(username, password) +} + +function saveToken (token, client, user) { + logger.debug('Saving token for client ' + client.id + ' and user ' + user.id + '.') + + const tokenObj = new OAuthToken({ + accessToken: token.accessToken, + accessTokenExpiresOn: token.accessTokenExpiresOn, + client: client.id, + refreshToken: token.refreshToken, + refreshTokenExpiresOn: token.refreshTokenExpiresOn, + user: user.id + }) + + return tokenObj.save(function (err, tokenCreated) { + if (err) throw err // node-oauth2-server library uses Promise.try + + tokenCreated.client = client + tokenCreated.user = user + + return tokenCreated + }) +} + +// --------------------------------------------------------------------------- + +module.exports = OAuthModel diff --git a/server/middlewares/index.js b/server/middlewares/index.js index b30a7be56..01043cd85 100644 --- a/server/middlewares/index.js +++ b/server/middlewares/index.js @@ -1,6 +1,6 @@ 'use strict' -const oauth2 = require('./oauth2') +const oauth = require('./oauth') const pagination = require('./pagination') const reqValidatorsMiddleware = require('./reqValidators') const search = require('./search') @@ -8,7 +8,7 @@ const sort = require('./sort') const secureMiddleware = require('./secure') const middlewares = { - oauth2: oauth2, + oauth: oauth, pagination: pagination, reqValidators: reqValidatorsMiddleware, search: search, diff --git a/server/middlewares/oauth2.js b/server/middlewares/oauth.js similarity index 89% rename from server/middlewares/oauth2.js rename to server/middlewares/oauth.js index 1defdc02e..3d7429f1d 100644 --- a/server/middlewares/oauth2.js +++ b/server/middlewares/oauth.js @@ -5,10 +5,10 @@ const OAuthServer = require('express-oauth-server') const logger = require('../helpers/logger') const oAuthServer = new OAuthServer({ - model: require('../models/users') + model: require('../lib/oauth-model') }) -const oAuth2 = { +const oAuth = { authenticate: authenticate, token: token } @@ -32,4 +32,4 @@ function token (req, res, next) { // --------------------------------------------------------------------------- -module.exports = oAuth2 +module.exports = oAuth diff --git a/server/models/oauth-client.js b/server/models/oauth-client.js new file mode 100644 index 000000000..048e5af48 --- /dev/null +++ b/server/models/oauth-client.js @@ -0,0 +1,33 @@ +const mongoose = require('mongoose') + +// --------------------------------------------------------------------------- + +const OAuthClientSchema = mongoose.Schema({ + clientSecret: String, + grants: Array, + redirectUris: Array +}) + +OAuthClientSchema.path('clientSecret').required(true) + +OAuthClientSchema.statics = { + list: list, + loadByIdAndSecret: loadByIdAndSecret, + loadFirstClient: loadFirstClient +} + +mongoose.model('OAuthClient', OAuthClientSchema) + +// --------------------------------------------------------------------------- + +function list (callback) { + return this.find(callback) +} + +function loadFirstClient (callback) { + return this.findOne({}, callback) +} + +function loadByIdAndSecret (id, clientSecret) { + return this.findOne({ _id: id, clientSecret: clientSecret }) +} diff --git a/server/models/oauth-token.js b/server/models/oauth-token.js new file mode 100644 index 000000000..5da5da417 --- /dev/null +++ b/server/models/oauth-token.js @@ -0,0 +1,34 @@ +const mongoose = require('mongoose') + +// --------------------------------------------------------------------------- + +const OAuthTokenSchema = mongoose.Schema({ + accessToken: String, + accessTokenExpiresOn: Date, + client: { type: mongoose.Schema.Types.ObjectId, ref: 'OAuthClient' }, + refreshToken: String, + refreshTokenExpiresOn: Date, + user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } +}) + +OAuthTokenSchema.path('accessToken').required(true) +OAuthTokenSchema.path('client').required(true) +OAuthTokenSchema.path('user').required(true) + +OAuthTokenSchema.statics = { + loadByRefreshToken: loadByRefreshToken, + loadByTokenAndPopulateUser: loadByTokenAndPopulateUser +} + +mongoose.model('OAuthToken', OAuthTokenSchema) + +// --------------------------------------------------------------------------- + +function loadByRefreshToken (refreshToken, callback) { + return this.findOne({ refreshToken: refreshToken }, callback) +} + +function loadByTokenAndPopulateUser (bearerToken, callback) { + // FIXME: allow to use callback + return this.findOne({ accessToken: bearerToken }).populate('user') +} diff --git a/server/models/user.js b/server/models/user.js new file mode 100644 index 000000000..130b49b55 --- /dev/null +++ b/server/models/user.js @@ -0,0 +1,28 @@ +const mongoose = require('mongoose') + +// --------------------------------------------------------------------------- + +const UserSchema = mongoose.Schema({ + password: String, + username: String +}) + +UserSchema.path('password').required(true) +UserSchema.path('username').required(true) + +UserSchema.statics = { + list: list, + loadByUsernameAndPassword: loadByUsernameAndPassword +} + +mongoose.model('User', UserSchema) + +// --------------------------------------------------------------------------- + +function list (callback) { + return this.find(callback) +} + +function loadByUsernameAndPassword (username, password, callback) { + return this.findOne({ username: username, password: password }, callback) +} diff --git a/server/models/users.js b/server/models/users.js deleted file mode 100644 index a1bdece23..000000000 --- a/server/models/users.js +++ /dev/null @@ -1,123 +0,0 @@ -const mongoose = require('mongoose') - -const logger = require('../helpers/logger') - -// --------------------------------------------------------------------------- - -const oAuthTokensSchema = mongoose.Schema({ - accessToken: String, - accessTokenExpiresOn: Date, - client: { type: mongoose.Schema.Types.ObjectId, ref: 'oAuthClients' }, - refreshToken: String, - refreshTokenExpiresOn: Date, - user: { type: mongoose.Schema.Types.ObjectId, ref: 'users' } -}) -const OAuthTokensDB = mongoose.model('oAuthTokens', oAuthTokensSchema) - -const oAuthClientsSchema = mongoose.Schema({ - clientSecret: String, - grants: Array, - redirectUris: Array -}) -const OAuthClientsDB = mongoose.model('oAuthClients', oAuthClientsSchema) - -const usersSchema = mongoose.Schema({ - password: String, - username: String -}) -const UsersDB = mongoose.model('users', usersSchema) - -// --------------------------------------------------------------------------- - -const Users = { - createClient: createClient, - createUser: createUser, - getAccessToken: getAccessToken, - getClient: getClient, - getClients: getClients, - getFirstClient: getFirstClient, - getRefreshToken: getRefreshToken, - getUser: getUser, - getUsers: getUsers, - saveToken: saveToken -} - -function createClient (secret, grants, callback) { - logger.debug('Creating client.') - - const mongoId = new mongoose.mongo.ObjectID() - return OAuthClientsDB.create({ _id: mongoId, clientSecret: secret, grants: grants }, function (err) { - if (err) return callback(err) - - return callback(null, mongoId) - }) -} - -function createUser (username, password, callback) { - logger.debug('Creating user.') - - return UsersDB.create({ username: username, password: password }, callback) -} - -function getAccessToken (bearerToken, callback) { - logger.debug('Getting access token (bearerToken: ' + bearerToken + ').') - - return OAuthTokensDB.findOne({ accessToken: bearerToken }).populate('user') -} - -function getFirstClient (callback) { - return OAuthClientsDB.findOne({}, callback) -} - -function getClient (clientId, clientSecret) { - logger.debug('Getting Client (clientId: ' + clientId + ', clientSecret: ' + clientSecret + ').') - - // TODO req validator - const mongoId = new mongoose.mongo.ObjectID(clientId) - return OAuthClientsDB.findOne({ _id: mongoId, clientSecret: clientSecret }) -} - -function getClients (callback) { - return OAuthClientsDB.find(callback) -} - -function getRefreshToken (refreshToken) { - logger.debug('Getting RefreshToken (refreshToken: ' + refreshToken + ').') - - return OAuthTokensDB.findOne({ refreshToken: refreshToken }) -} - -function getUser (username, password) { - logger.debug('Getting User (username: ' + username + ', password: ' + password + ').') - return UsersDB.findOne({ username: username, password: password }) -} - -function getUsers (callback) { - return UsersDB.find(callback) -} - -function saveToken (token, client, user) { - logger.debug('Saving token for client ' + client.id + ' and user ' + user.id + '.') - - const tokenToCreate = { - accessToken: token.accessToken, - accessTokenExpiresOn: token.accessTokenExpiresOn, - client: client.id, - refreshToken: token.refreshToken, - refreshTokenExpiresOn: token.refreshTokenExpiresOn, - user: user.id - } - - return OAuthTokensDB.create(tokenToCreate, function (err, tokenCreated) { - if (err) throw err // node-oauth2-server library uses Promise.try - - tokenCreated.client = client - tokenCreated.user = user - - return tokenCreated - }) -} - -// --------------------------------------------------------------------------- - -module.exports = Users -- 2.41.0