[oauth] start oauth auth_code server implementation
This commit is contained in:
58
server/api/controller/oauth.js
Normal file
58
server/api/controller/oauth.js
Normal file
@@ -0,0 +1,58 @@
|
||||
const crypto = require('crypto')
|
||||
const { promisify } = require('util')
|
||||
const randomBytes = promisify(crypto.randomBytes)
|
||||
const { oauth_client: OAuthClient, oauth_token: OAuthToken,
|
||||
oauth_code: OAuthCode } = require('../models')
|
||||
|
||||
async function randomString(len = 16) {
|
||||
const bytes = await randomBytes(len*8)
|
||||
return crypto
|
||||
.createHash('sha1')
|
||||
.update(bytes)
|
||||
.digest('hex')
|
||||
}
|
||||
|
||||
|
||||
const oauthController = {
|
||||
|
||||
async getClient (req, res) {
|
||||
const client_id = req.params.client_id
|
||||
const client = await OAuthClient.findOne({ where: { client_id }})
|
||||
console.error('ma non ho trovato il client ', client_id, client )
|
||||
res.json(client)
|
||||
},
|
||||
|
||||
async createClient (req, res) {
|
||||
|
||||
const client = {
|
||||
name: req.body.client_name,
|
||||
redirectUris: req.body.redirect_uris || 'urn:ietf:wg:oauth:2.0:oob',
|
||||
scopes: req.body.scopes || 'write',
|
||||
client_id: await randomString(256),
|
||||
client_secret: await randomString(256)
|
||||
}
|
||||
res.json(await OAuthClient.create(client))
|
||||
},
|
||||
|
||||
async associate (req, res) {
|
||||
const { client_id, redirect_uri, response_type } = req.query
|
||||
console.error('dentro associate ', client_id, redirect_uri, response_type )
|
||||
},
|
||||
|
||||
model: {
|
||||
async getClient (clientId, clientSecret) {
|
||||
console.error(`model getClient ${clientId} / ${clientSecret}`)
|
||||
const client = await OAuthClient.findByPk(clientId)
|
||||
client.grants = ['authorization_code']
|
||||
return client || false
|
||||
},
|
||||
|
||||
async saveAuthorizationCode(code, client, user) {
|
||||
console.error('dentro save auth code ', client, user, code)
|
||||
const ret = await OAuthCode.create(code)
|
||||
return ret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = oauthController
|
||||
@@ -1,6 +1,5 @@
|
||||
const express = require('express')
|
||||
const multer = require('multer')
|
||||
const cookieParser = require('cookie-parser')
|
||||
const bodyParser = require('body-parser')
|
||||
const cors = require('cors')()
|
||||
|
||||
@@ -12,6 +11,7 @@ const settingsController = require('./controller/settings')
|
||||
const instanceController = require('./controller/instance')
|
||||
const apUserController = require('./controller/ap_user')
|
||||
const resourceController = require('./controller/resource')
|
||||
const oauthController = require('./controller/oauth')
|
||||
|
||||
const storage = require('./storage')
|
||||
const upload = multer({ storage })
|
||||
@@ -19,9 +19,8 @@ const upload = multer({ storage })
|
||||
const debug = require('debug')('api')
|
||||
|
||||
const api = express.Router()
|
||||
api.use(cookieParser())
|
||||
api.use(bodyParser.urlencoded({ extended: false }))
|
||||
api.use(bodyParser.json())
|
||||
api.use(express.urlencoded({ extended: false }))
|
||||
api.use(express.json())
|
||||
|
||||
// AUTH
|
||||
api.post('/auth/login', userController.login)
|
||||
@@ -94,6 +93,9 @@ api.put('/resources/:resource_id', isAdmin, resourceController.hide)
|
||||
api.delete('/resources/:resource_id', isAdmin, resourceController.remove)
|
||||
api.get('/resources', isAdmin, resourceController.getAll)
|
||||
|
||||
api.get('/client/:client_id', isAuth, oauthController.getClient)
|
||||
api.post('/client', oauthController.createClient)
|
||||
|
||||
// Handle 404
|
||||
api.use((req, res) => {
|
||||
debug('404 Page not found: %s', req.path)
|
||||
|
||||
19
server/api/models/oauth_client.js
Normal file
19
server/api/models/oauth_client.js
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
const OAuthClient = sequelize.define('oauth_client', {
|
||||
client_id: {
|
||||
type: DataTypes.STRING,
|
||||
primaryKey: true
|
||||
},
|
||||
name: DataTypes.STRING,
|
||||
scopes: DataTypes.STRING,
|
||||
client_secret: DataTypes.STRING,
|
||||
redirectUris: DataTypes.STRING
|
||||
}, {})
|
||||
|
||||
OAuthClient.associate = function (models) {
|
||||
OAuthClient.belongsTo(models.user)
|
||||
}
|
||||
|
||||
return OAuthClient
|
||||
}
|
||||
18
server/api/models/oauth_code.js
Normal file
18
server/api/models/oauth_code.js
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
const OAuthCode = sequelize.define('oauth_code', {
|
||||
authorizationCode: {
|
||||
type: DataTypes.STRING,
|
||||
primaryKey: true
|
||||
},
|
||||
scope: DataTypes.STRING,
|
||||
redirect_uri: DataTypes.STRING
|
||||
}, {})
|
||||
|
||||
OAuthCode.associate = function (models) {
|
||||
OAuthCode.belongsTo(models.user)
|
||||
OAuthCode.belongsTo(models.oauth_client)
|
||||
}
|
||||
|
||||
return OAuthCode
|
||||
}
|
||||
15
server/api/models/oauth_token.js
Normal file
15
server/api/models/oauth_token.js
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
const OAuthToken = sequelize.define('oauth_token', {
|
||||
access_token: DataTypes.STRING,
|
||||
refresh_token: DataTypes.STRING,
|
||||
scope: DataTypes.STRING,
|
||||
}, {})
|
||||
|
||||
OAuthToken.associate = function (models) {
|
||||
OAuthToken.belongsTo(models.user)
|
||||
OAuthToken.belongsTo(models.oauth_client)
|
||||
}
|
||||
|
||||
return OAuthToken
|
||||
}
|
||||
74
server/api/oauth.js
Normal file
74
server/api/oauth.js
Normal file
@@ -0,0 +1,74 @@
|
||||
const express = require('express')
|
||||
const OAuthServer = require('express-oauth-server')
|
||||
const oauth = express.Router()
|
||||
const bodyParser = require('body-parser')
|
||||
const oauthController = require('./controller/oauth')
|
||||
|
||||
const oauthServer = new OAuthServer({
|
||||
model: oauthController.model,
|
||||
useErrorHandler: true,
|
||||
debug: true,
|
||||
authenticateHandler: { handle(req) { return req.user } }
|
||||
})
|
||||
|
||||
oauth.oauth = oauthServer
|
||||
oauth.use(bodyParser.json())
|
||||
oauth.use(bodyParser.urlencoded({ extended: false }))
|
||||
|
||||
// post token
|
||||
// oauth.post(oauthServer.authorize())
|
||||
oauth.post('/token', (req, res, next) => {
|
||||
return oauthServer.token()(req, res, next)
|
||||
.then(code => {
|
||||
console.error('dopo il token', code)
|
||||
})
|
||||
.catch(e => console.error('nel catch ', e))
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* create a new application
|
||||
*/
|
||||
oauth.get('/authorize', async (req, res, next) => {
|
||||
if (!req.user) {
|
||||
return res.redirect(`/?ref=login&redirect=${req.path}&client_id=${req.query.client_id}&redirect_uri=${req.query.redirect_uri}`)
|
||||
}
|
||||
|
||||
return oauthServer.authorize()(req, res, next).then(code => {
|
||||
console.error('dentro authorize?', code)
|
||||
console.error(req.locals)
|
||||
return
|
||||
// return res.redirect(`/?ref=authorize&client_id=${req.query.client_id}&redirect_uri=${req.query.redirect_uri}&code=${code}`)
|
||||
}).catch(e => { console.error('porcodio catch ', e) })
|
||||
})
|
||||
|
||||
oauth.post('/authorize', (req, res, next) => {
|
||||
if (!req.user) {
|
||||
return res.redirect(`/?ref=login&redirect=${req.path}&client_id=${req.query.client_id}&redirect_uri=${req.query.redirect_uri}`)
|
||||
}
|
||||
console.error('sono nel post di authorize!')
|
||||
const ret = oauthServer.authorize()
|
||||
console.error('PORCODIO ', ret)
|
||||
return ret(req, res, next).then(code => {
|
||||
console.error('DAJE CHE ARRIVO QUI ', code)
|
||||
console.error(req.locals)
|
||||
next()
|
||||
}).catch(e => console.error('CATCH ', e))
|
||||
})
|
||||
|
||||
oauth.get('/login', (req, res) => {
|
||||
res.render('login', {
|
||||
client_id: req.query.client_id,
|
||||
redirect_uri: req.query.redirect_uri,
|
||||
redirect: req.query.redirect,
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
oauth.use((err, req, res, next) => {
|
||||
res.status(400).json(err)
|
||||
})
|
||||
|
||||
// oauth.post('/login', )
|
||||
|
||||
module.exports = oauth
|
||||
30
server/migrations/20191226001504-oauth_client.js
Normal file
30
server/migrations/20191226001504-oauth_client.js
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
module.exports = {
|
||||
up: (queryInterface, Sequelize) => {
|
||||
return queryInterface.createTable('oauth_clients', {
|
||||
client_id: {
|
||||
type: Sequelize.STRING,
|
||||
primaryKey: true
|
||||
},
|
||||
name: Sequelize.STRING,
|
||||
scopes: Sequelize.STRING,
|
||||
client_secret: Sequelize.STRING,
|
||||
redirectUris: Sequelize.STRING,
|
||||
createdAt: { type: Sequelize.DATE, allowNull: false },
|
||||
updatedAt: { type: Sequelize.DATE, allowNull: false },
|
||||
userId: {
|
||||
type: Sequelize.INTEGER,
|
||||
references: {
|
||||
model: 'users',
|
||||
key: 'id'
|
||||
},
|
||||
onUpdate: 'CASCADE',
|
||||
onDelete: 'CASCADE'
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
down: (queryInterface, Sequelize) => {
|
||||
return queryInterface.dropTable('oauth_clients')
|
||||
}
|
||||
}
|
||||
37
server/migrations/20191226102934-oauth_code.js
Normal file
37
server/migrations/20191226102934-oauth_code.js
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
module.exports = {
|
||||
up: (queryInterface, Sequelize) => {
|
||||
return queryInterface.createTable('oauth_codes', {
|
||||
authorizationCode: {
|
||||
type: Sequelize.STRING,
|
||||
primaryKey: true
|
||||
},
|
||||
scope: Sequelize.STRING,
|
||||
redirect_uri: Sequelize.STRING,
|
||||
createdAt: { type: Sequelize.DATE, allowNull: false },
|
||||
updatedAt: { type: Sequelize.DATE, allowNull: false },
|
||||
oauthClientClientId: {
|
||||
type: Sequelize.INTEGER,
|
||||
references: {
|
||||
model: 'oauth_clients',
|
||||
key: 'client_id'
|
||||
},
|
||||
onUpdate: 'CASCADE',
|
||||
onDelete: 'CASCADE'
|
||||
},
|
||||
userId: {
|
||||
type: Sequelize.INTEGER,
|
||||
references: {
|
||||
model: 'users',
|
||||
key: 'id'
|
||||
},
|
||||
onUpdate: 'CASCADE',
|
||||
onDelete: 'CASCADE'
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
down: (queryInterface, Sequelize) => {
|
||||
return queryInterface.dropTable('oauth_codes')
|
||||
}
|
||||
}
|
||||
84
server/model.js
Normal file
84
server/model.js
Normal file
@@ -0,0 +1,84 @@
|
||||
const crypto = require('crypto')
|
||||
const { promisify } = require('util')
|
||||
const randomBytes = promisify(crypto.randomBytes)
|
||||
|
||||
async function randomString(len = 16) {
|
||||
const bytes = await randomBytes(len*8)
|
||||
return crypto
|
||||
.createHash('sha1')
|
||||
.update(bytes)
|
||||
.digest('hex')
|
||||
}
|
||||
|
||||
const OAuth = {
|
||||
clients: [
|
||||
{ clientId : 'confidentialApplication', clientSecret : 'topSecret',
|
||||
redirectUris : ['https://localhost:13120/asdf', 'https://example-app.com/callback', 'https://oauthdebugger.com/debug'],
|
||||
grants: ['password', 'authorization_code', 'client_credentials']
|
||||
},
|
||||
{
|
||||
clientId: '1766891b7fb5fda4235dc7f0dde70fcd783371c2', clientSecret: 'ed6fdc050a415f178f2ac8428b76734edef75e5c',
|
||||
grants: ['authorization_code'], redirectUris: ['urn:ietf:wg:oauth:2.0:oob'], scopes: ['write'], state: 'a'
|
||||
}
|
||||
],
|
||||
tokens: [],
|
||||
users: [{ id : '123', username: 'thomseddon', password: 'nightworld' }],
|
||||
|
||||
getAccessToken (bearerToken) {
|
||||
console.error('dentro get access token', bearerToken, OAuth.tokens)
|
||||
const tokens = OAuth.tokens.filter(token => token.accessToken === bearerToken)
|
||||
return tokens.length ? tokens[0] : false
|
||||
},
|
||||
verifyScope (accessToken, scope) {
|
||||
console.error('dentro verify scope', scope)
|
||||
},
|
||||
getRefreshToken (bearerToken) {
|
||||
console.error('dentro refresh token')
|
||||
const tokens = OAuth.tokens.filter( token => token.refreshToken === bearerToken )
|
||||
return tokens.length ? tokens[0] : false
|
||||
},
|
||||
getClientCredentials () {
|
||||
console.error('dentro get client credentials')
|
||||
},
|
||||
getClient (clientId, clientSecret) {
|
||||
console.error(`getClient ${clientId} / ${clientSecret}`)
|
||||
const clients = OAuth.clients.filter( client => client.clientId === clientId)
|
||||
console.error(clients)
|
||||
return clients.length ? clients[0] : false
|
||||
},
|
||||
getAuthorizationCode(authorizationCode) {
|
||||
console.error('get auth code')
|
||||
},
|
||||
revokeAuthorizationCode (code) {
|
||||
console.error('dentro revoke auth code ', code)
|
||||
},
|
||||
async createClient (client) {
|
||||
client.client_id = await randomString(256)
|
||||
client.client_secret = await randomString(256)
|
||||
OAuth.clients.push(client)
|
||||
return client
|
||||
},
|
||||
saveAuthorizationCode(code, client, user) {
|
||||
console.error('dentro save auth code')
|
||||
const ret = {
|
||||
...code,
|
||||
user,
|
||||
client
|
||||
}
|
||||
OAuth.tokens.push(ret)
|
||||
console.error('DIOCANEEEE salvo auth code!', OAuth.tokens)
|
||||
return ret
|
||||
},
|
||||
saveToken (token) {
|
||||
console.error('dentro save token')
|
||||
},
|
||||
// saveAuthorizationCode (token, client, user) {
|
||||
// console.error('dentro save auth code')
|
||||
// return true
|
||||
// },
|
||||
getUser (username, password) {
|
||||
console.error('dentro get user')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = OAuth
|
||||
@@ -3,6 +3,7 @@ const config = require('config')
|
||||
const express = require('express')
|
||||
const cors = require('cors')
|
||||
const api = require('./api')
|
||||
const oauth = require('./api/oauth')
|
||||
const cookieParser = require('cookie-parser')
|
||||
const federation = require('./federation')
|
||||
const webfinger = require('./federation/webfinger')
|
||||
@@ -10,42 +11,44 @@ const { spamFilter } = require('./federation/helpers')
|
||||
const debug = require('debug')('routes')
|
||||
const exportController = require('./api/controller/export')
|
||||
const helpers = require('./helpers')
|
||||
const router = express.Router()
|
||||
const app = express()
|
||||
|
||||
router.use((req, res, next) => {
|
||||
app.use((req, res, next) => {
|
||||
debug(req.path)
|
||||
next()
|
||||
})
|
||||
|
||||
// ignore unimplemented ping url from fediverse
|
||||
router.use(spamFilter)
|
||||
app.use(spamFilter)
|
||||
|
||||
// serve favicon and static content
|
||||
router.use('/favicon.ico', express.static(path.resolve(config.favicon || './assets/favicon.ico')))
|
||||
router.use('/logo.png', express.static('./static/gancio.png'))
|
||||
router.use('/media/', express.static(config.upload_path))
|
||||
app.use('/favicon.ico', express.static(path.resolve(config.favicon || './assets/favicon.ico')))
|
||||
app.use('/logo.png', express.static('./static/gancio.png'))
|
||||
app.use('/media/', express.static(config.upload_path))
|
||||
|
||||
// get instance settings
|
||||
router.use(cookieParser())
|
||||
router.use(helpers.initMiddleware)
|
||||
app.use(cookieParser())
|
||||
app.use(helpers.initMiddleware)
|
||||
|
||||
app.use('/oauth', oauth)
|
||||
|
||||
// rss/ics/atom feed
|
||||
router.get('/feed/:type', cors(), exportController.export)
|
||||
app.get('/feed/:type', cors(), exportController.export)
|
||||
|
||||
// api!
|
||||
router.use('/api', api)
|
||||
app.use('/api', api)
|
||||
|
||||
// federation api / activitypub / webfinger / nodeinfo
|
||||
router.use('/.well-known', webfinger)
|
||||
router.use('/federation', federation)
|
||||
app.use('/.well-known', webfinger)
|
||||
app.use('/federation', federation)
|
||||
|
||||
// Handle 500
|
||||
router.use((error, req, res, next) => {
|
||||
debug('Error 500: %s', error)
|
||||
res.status(500).send('500: Internal Server Error')
|
||||
})
|
||||
// // Handle 500
|
||||
// app.use((error, req, res, next) => {
|
||||
// debug('Error 500: %s', error)
|
||||
// res.status(500).send('500: Internal Server Error')
|
||||
// })
|
||||
|
||||
// remaining request goes to nuxt
|
||||
// first nuxt component is ./pages/index.vue
|
||||
|
||||
module.exports = router
|
||||
module.exports = app
|
||||
|
||||
Reference in New Issue
Block a user