[oauth] start oauth auth_code server implementation
This commit is contained in:
parent
c510541c50
commit
7ab81be418
17 changed files with 1631 additions and 838 deletions
|
@ -1,5 +1,8 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
|
||||
unreleased
|
||||
- oauth server implementation
|
||||
|
||||
### 1.17.14
|
||||
[locale] add catalan
|
||||
[fix] fedi outbox
|
||||
|
|
12
layouts/modal.vue
Normal file
12
layouts/modal.vue
Normal file
|
@ -0,0 +1,12 @@
|
|||
<template lang='pug'>
|
||||
el-container
|
||||
el-header
|
||||
el-row(:gutter='20')
|
||||
el-col(:span='12' :offset='6')
|
||||
el-card.mt-5
|
||||
h4(slot='header') <img src='/favicon.ico'/> {{$route.name}}
|
||||
nuxt
|
||||
</template>
|
||||
<style lang="less">
|
||||
@import '../assets/style.less';
|
||||
</style>
|
|
@ -67,7 +67,8 @@
|
|||
"follow": "Segui",
|
||||
"n_resources": "nessuna risorsa|una risorsa|{n} risorse",
|
||||
"resources": "Risorse",
|
||||
"moderation": "Moderazione"
|
||||
"moderation": "Moderazione",
|
||||
"authorize": "Autorizza"
|
||||
},
|
||||
"login": {
|
||||
"description": "Entrando puoi pubblicare nuovi eventi.",
|
||||
|
|
33
package.json
33
package.json
|
@ -5,9 +5,9 @@
|
|||
"author": "lesion",
|
||||
"scripts": {
|
||||
"dev:nuxt": "cross-env NODE_ENV=development nuxt dev",
|
||||
"dev": "cross-env DEBUG=*,-babel,-follow-redirects,-send,-body-parser:*,-express:*,-connect:*,-sequelize:* NODE_ENV=development node server/index.js",
|
||||
"dev": "cross-env DEBUG=*,-babel*,-follow-redirects,-send,-body-parser:*,-express:*,-connect:*,-sequelize:* NODE_ENV=development node server/index.js",
|
||||
"build": "nuxt build",
|
||||
"start": "cross-env DEBUG=*,-babel,-follow-redirects,-send,-body-parser:*,-express:*,-connect:*,-sequelize:* NODE_ENV=production node server/cli.js",
|
||||
"start": "cross-env DEBUG=*,-babel*,-follow-redirects,-send,-body-parser:*,-express:*,-connect:*,-sequelize:* NODE_ENV=production node server/cli.js",
|
||||
"lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
|
||||
"doc": "cd docs && bundle exec jekyll b",
|
||||
"doc:dev": "cd docs && bundle exec jekyll s --drafts",
|
||||
|
@ -50,26 +50,27 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"@nuxtjs/auth": "^4.8.4",
|
||||
"@nuxtjs/axios": "^5.8.0",
|
||||
"@nuxtjs/axios": "^5.9.0",
|
||||
"accept-language": "^3.0.18",
|
||||
"axios": "^0.19.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"body-parser": "^1.18.3",
|
||||
"bootstrap": "^4.4.1",
|
||||
"config": "^3.2.4",
|
||||
"consola": "^2.11.0",
|
||||
"consola": "^2.11.1",
|
||||
"cookie-parser": "^1.4.4",
|
||||
"cors": "^2.8.5",
|
||||
"cross-env": "^6.0.0",
|
||||
"dayjs": "^1.8.17",
|
||||
"dayjs": "^1.8.18",
|
||||
"element-ui": "^2.13.0",
|
||||
"email-templates": "^6.0.6",
|
||||
"email-templates": "^6.1.1",
|
||||
"express": "^4.17.1",
|
||||
"express-jwt": "^5.3.1",
|
||||
"express-middleware-log": "^1.2.0",
|
||||
"express-oauth-server": "^2.0.0",
|
||||
"http-signature": "^1.3.1",
|
||||
"ics": "^2.16.0",
|
||||
"inquirer": "^7.0.0",
|
||||
"inquirer": "^7.0.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"less": "^3.10.3",
|
||||
"lodash": "^4.17.14",
|
||||
|
@ -78,20 +79,20 @@
|
|||
"morgan": "^1.9.1",
|
||||
"multer": "^1.4.2",
|
||||
"node-fetch": "^2.6.0",
|
||||
"nuxt": "^2.10.2",
|
||||
"nuxt": "^2.11.0",
|
||||
"nuxt-express-module": "^0.0.11",
|
||||
"pg": "^7.14.0",
|
||||
"pg": "^7.15.1",
|
||||
"sanitize-html": "^1.20.1",
|
||||
"sass-loader": "^8.0.0",
|
||||
"sequelize": "^5.21.2",
|
||||
"sequelize": "^5.21.3",
|
||||
"sequelize-cli": "^5.5.1",
|
||||
"sharp": "^0.23.4",
|
||||
"sqlite3": "^4.1.1",
|
||||
"url": "^0.11.0",
|
||||
"v-calendar": "^1.0.0-beta.16",
|
||||
"v-calendar": "^1.0.0-beta.23",
|
||||
"vue-awesome": "^4.0.0",
|
||||
"vue-clipboard2": "^0.3.1",
|
||||
"vue-i18n": "^8.15.1",
|
||||
"vue-i18n": "^8.15.3",
|
||||
"yargs": "^15.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -100,18 +101,18 @@
|
|||
"eslint": "^6.7.2",
|
||||
"eslint-config-prettier": "^6.7.0",
|
||||
"eslint-config-standard": ">=14.1.0",
|
||||
"eslint-loader": "^3.0.0",
|
||||
"eslint-plugin-import": ">=2.17.3",
|
||||
"eslint-loader": "^3.0.3",
|
||||
"eslint-plugin-import": ">=2.19.1",
|
||||
"eslint-plugin-jest": ">=23.1.1",
|
||||
"eslint-plugin-node": ">=10.0.0",
|
||||
"eslint-plugin-nuxt": ">=0.5.0",
|
||||
"eslint-plugin-prettier": "^3.1.1",
|
||||
"eslint-plugin-prettier": "^3.1.2",
|
||||
"eslint-plugin-promise": ">=4.0.1",
|
||||
"eslint-plugin-standard": ">=4.0.1",
|
||||
"eslint-plugin-vue": "^6.0.1",
|
||||
"jsdoc": "^3.6.3",
|
||||
"less-loader": "^5.0.0",
|
||||
"nodemon": "^2.0.1",
|
||||
"nodemon": "^2.0.2",
|
||||
"prettier": "^1.19.1",
|
||||
"pug-plain-loader": "^1.0.0",
|
||||
"webpack-cli": "^3.3.10"
|
||||
|
|
52
pages/Authorize.vue
Normal file
52
pages/Authorize.vue
Normal file
|
@ -0,0 +1,52 @@
|
|||
<template lang='pug'>
|
||||
//- el-card.mt-5
|
||||
//- div(slot='header')
|
||||
//- h4 <img src='/favicon.ico'/> App authorization
|
||||
div(v-if='client')
|
||||
h5 <u>{{$auth.user.email}}</u>
|
||||
p External application <b>{{client.name}}</b> want following permission grants:
|
||||
ul
|
||||
li(v-for="scope in $route.query.scope.split(' ')") {{scope}}
|
||||
span You will be redirected to <b>{{$route.query.redirect_uri}}</b>
|
||||
el-row.mt-3(justify='center')
|
||||
el-col(:span='12' :offset='6' style='text-align: center')
|
||||
a(:href='authorizeURL')
|
||||
el-button.mr-1(plain type='success') {{$t('common.authorize')}}
|
||||
a(to='/')
|
||||
el-button.mt-1(plain type='warning') {{$t('common.cancel')}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapState } from 'vuex'
|
||||
import { Message } from 'element-ui'
|
||||
import get from 'lodash/get'
|
||||
|
||||
export default {
|
||||
layout: 'modal',
|
||||
name: 'Authorize',
|
||||
middleware: ['auth'],
|
||||
head: { title: 'Authorize' },
|
||||
data () {
|
||||
return {
|
||||
client: { name: 'Test' }
|
||||
}
|
||||
},
|
||||
async asyncData ({ $axios, query }) {
|
||||
// retrieve client validity
|
||||
try {
|
||||
const client = await $axios.$get(`/client/${query.client_id}`)
|
||||
return { client }
|
||||
} catch(e) {
|
||||
console.error(e)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['settings']),
|
||||
authorizeURL () {
|
||||
const { scope, response_type, client_id, redirect_uri, state } = this.$route.query
|
||||
const query = `client_id=${client_id}&response_type=${response_type}&scope=${scope}&redirect_uri=${redirect_uri}&state=${state}`
|
||||
return `oauth/authorize?${query}`
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
|
@ -31,11 +31,13 @@
|
|||
el-tab-pane
|
||||
span(slot='label') <v-icon name='map-marker-alt'/> {{$t('common.where')}}
|
||||
p(v-html="$t('event.where_description')")
|
||||
|
||||
span {{event.place.name}}
|
||||
el-select.mb-3(v-model='event.place.name'
|
||||
@keypress.tab='testBlur'
|
||||
@change='placeChoosed'
|
||||
filterable allow-create
|
||||
default-first-option
|
||||
@blur='testBlur'
|
||||
)
|
||||
el-option(v-for='place in places' :label='place.name' :value='place.name' :key='place.id')
|
||||
div {{$t("common.address")}}
|
||||
|
@ -92,6 +94,8 @@
|
|||
//- MEDIA / FLYER / POSTER
|
||||
el-tab-pane
|
||||
span(slot='label') {{$t('common.media')}} <v-icon name='image'/>
|
||||
div.mb-2 {{$t('event.media_description')}}
|
||||
img(:src='mediaUrl' @load='imageLoaded')
|
||||
el-upload.text-center(
|
||||
action=''
|
||||
:limit="1"
|
||||
|
@ -100,12 +104,10 @@
|
|||
accept='image/*'
|
||||
:on-remove='cleanFile'
|
||||
:on-change='uploadedFile'
|
||||
:multiple='false'
|
||||
:file-list="fileList"
|
||||
)
|
||||
:multiple='false')
|
||||
i.el-icon-upload
|
||||
div.el-upload__text {{$t('event.media_description')}}
|
||||
el-button.float-right(@click='done' :disabled='!couldProceed') {{edit?$t('common.edit'):$t('common.send')}}
|
||||
el-input(v-model='mediaUrl' @blur='checkMediaUrl')
|
||||
el-button.mt-2.float-right(@click='done' :disabled='!couldProceed') {{edit?$t('common.edit'):$t('common.send')}}
|
||||
|
||||
</template>
|
||||
<script>
|
||||
|
@ -148,7 +150,8 @@ export default {
|
|||
date: null,
|
||||
time: { start: '20:00', end: null },
|
||||
edit: false,
|
||||
loading: false
|
||||
loading: false,
|
||||
mediaUrl: '',
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -311,6 +314,33 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
...mapActions(['addEvent', 'updateEvent', 'updateMeta', 'updateEvents']),
|
||||
testBlur (e) {
|
||||
console.error('nel blur!')
|
||||
this.event.place.name = e.target.value
|
||||
},
|
||||
imageLoaded () {
|
||||
console.error('image loaded!')
|
||||
},
|
||||
async checkMediaUrl () {
|
||||
// if (!this.mediaUrl) return
|
||||
// this.fileList.push({ name: this.mediaUrl, url: this.mediaUrl })
|
||||
// const img = document.createElement('img')
|
||||
// const c = document.createElement('canvas')
|
||||
// const ctx = c.getContext('2d')
|
||||
// img.crossOrigin = ''
|
||||
// img.src = this.mediaUrl
|
||||
// console.error('image loaded')
|
||||
// c.width = this.naturalWidth
|
||||
// c.height = this.naturalHeight
|
||||
// ctx.drawImage(this, 0, 0)
|
||||
// c.toBlob( raw => {
|
||||
// this.event.image = { name: this.mediaUrl, raw}
|
||||
// }, 'image/jpeg', 0.9)
|
||||
// }
|
||||
// fetch(this.mediaUrl, { mode: 'cors' })
|
||||
// .then( ret => ret.blob() )
|
||||
// .then( raw => { if (!raw) return; this.event.image = { name: this.mediaUrl, raw }})
|
||||
},
|
||||
recurrentDays () {
|
||||
if (this.event.type !== 'recurrent' || !this.date || !this.date.length) { return }
|
||||
const type = this.event.recurrent.type
|
||||
|
@ -326,6 +356,7 @@ export default {
|
|||
this.activeTab = String(Number(this.activeTab - 1))
|
||||
},
|
||||
placeChoosed () {
|
||||
console.error('dentro place choosed')
|
||||
const place = this.places.find(p => p.name === this.event.place.name)
|
||||
if (place && place.address) {
|
||||
this.event.place.address = place.address
|
||||
|
|
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
|
||||
|
|
Loading…
Reference in a new issue