2020-05-17 04:55:08 +00:00
|
|
|
const { Controller } = require('libflitter')
|
2020-08-13 06:56:33 +00:00
|
|
|
const uuid = require('uuid').v4
|
2020-05-17 04:55:08 +00:00
|
|
|
|
|
|
|
class ReflectController extends Controller {
|
|
|
|
static get services() {
|
2020-07-13 14:35:11 +00:00
|
|
|
return [...super.services, 'routers', 'models', 'activity']
|
2020-05-17 04:55:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async get_tokens(req, res, next) {
|
|
|
|
const Oauth2BearerToken = this.models.get('auth::Oauth2BearerToken')
|
|
|
|
const tokens = await Oauth2BearerToken.find({
|
|
|
|
expires: { $gt: new Date },
|
|
|
|
userID: req.user.id,
|
|
|
|
})
|
|
|
|
|
|
|
|
const Client = this.models.get('oauth:Client')
|
|
|
|
const data = []
|
|
|
|
for ( const token of tokens ) {
|
|
|
|
const client = await Client.findOne({ uuid: token.clientID })
|
2020-05-31 01:16:10 +00:00
|
|
|
let client_display = client && client.active ? client.name : req.T('api.nonexistent_client')
|
2020-05-17 04:55:08 +00:00
|
|
|
|
|
|
|
data.push({
|
|
|
|
id: token.id,
|
|
|
|
token: token.accessToken,
|
|
|
|
client_id: token.clientID,
|
|
|
|
client_display,
|
|
|
|
expires: token.expires,
|
|
|
|
user_id: token.userID,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return res.api(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
async get_token(req, res, next) {
|
|
|
|
const Oauth2BearerToken = this.models.get('auth::Oauth2BearerToken')
|
|
|
|
const token = await Oauth2BearerToken.findById(req.params.id)
|
|
|
|
|
|
|
|
if ( !token || token.userID !== req.user.id || token.expires <= new Date )
|
|
|
|
return res.status(404)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(req.T('api.token_not_found'))
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
return res.api({
|
|
|
|
id: token.id,
|
|
|
|
token: token.accessToken,
|
|
|
|
client_id: token.clientID,
|
|
|
|
expires: token.expires,
|
|
|
|
user_id: token.userID,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
async create_token(req, res, next) {
|
|
|
|
const Oauth2BearerToken = this.models.get('auth::Oauth2BearerToken')
|
|
|
|
|
|
|
|
if ( !req.body.client_id )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(`${req.T('api.missing_field')} client_id`)
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
const Client = this.models.get('oauth:Client')
|
|
|
|
const client = await Client.findOne({uuid: req.body.client_id})
|
|
|
|
if ( !client || !client.active )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(`${req.T('common.invalid')} client_id.`)
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
if ( !req.user.can(`oauth:client:${client.id}:view`) )
|
|
|
|
return res.status(401)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(req.T('api.insufficient_permissions'))
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
const expires = new Date()
|
|
|
|
expires.setDate(expires.getDate() + 7)
|
|
|
|
|
|
|
|
const token = new Oauth2BearerToken({
|
|
|
|
accessToken: String(uuid()).replace(/-/g, ''),
|
|
|
|
clientID: client.uuid,
|
|
|
|
expires,
|
|
|
|
userID: req.user.id,
|
|
|
|
})
|
|
|
|
|
|
|
|
await token.save()
|
2020-07-13 14:35:11 +00:00
|
|
|
await this.activity.api_token_created({ req, oauth_client_id: client.uuid })
|
2020-05-17 04:55:08 +00:00
|
|
|
return res.api({
|
|
|
|
id: token.id,
|
|
|
|
token: token.accessToken,
|
|
|
|
client_id: token.clientID,
|
|
|
|
expires: token.expires,
|
|
|
|
user_id: token.userID,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
async update_token(req, res, next) {
|
|
|
|
const Oauth2BearerToken = this.models.get('auth::Oauth2BearerToken')
|
|
|
|
const token = await Oauth2BearerToken.findById(req.params.id)
|
|
|
|
|
|
|
|
if ( !token || token.userID !== req.user.id || token.expires <= new Date )
|
|
|
|
return res.status(404)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(req.T('api.token_not_found'))
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
if ( !req.body.client_id )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(`${req.T('api.missing_field')} client_id`)
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
const Client = this.models.get('oauth:Client')
|
|
|
|
const client = await Client.findOne({uuid: req.body.client_id})
|
|
|
|
|
|
|
|
if ( !client || !client.active || !req.user.can(`oauth:client:${client.id}:view`) )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(`${req.T('common.invalid')} client_id.`)
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
token.client_id = client.uuid
|
|
|
|
await token.save()
|
|
|
|
return res.api()
|
|
|
|
}
|
|
|
|
|
|
|
|
async delete_token(req, res, next) {
|
|
|
|
const Oauth2BearerToken = this.models.get('auth::Oauth2BearerToken')
|
|
|
|
const token = await Oauth2BearerToken.findById(req.params.id)
|
|
|
|
|
|
|
|
if ( !token || token.userID !== req.user.id || token.expires <= new Date )
|
|
|
|
return res.status(404)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(req.T('api.token_not_found'))
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
await token.delete()
|
|
|
|
return res.api()
|
|
|
|
}
|
|
|
|
|
2020-05-21 02:17:07 +00:00
|
|
|
api_scopes() {
|
2020-05-17 04:55:08 +00:00
|
|
|
const routers = this.routers.canonical_items
|
|
|
|
const scopes = []
|
|
|
|
|
|
|
|
for ( const prefix in routers ) {
|
|
|
|
if ( !routers.hasOwnProperty(prefix) ) continue
|
|
|
|
const router = routers[prefix].schema
|
|
|
|
|
|
|
|
const supported_verbs = ['get', 'post', 'put', 'delete', 'copy', 'patch']
|
|
|
|
for ( const verb of supported_verbs ) {
|
|
|
|
if ( typeof router[verb] === 'object' ) {
|
|
|
|
const defs = router[verb]
|
|
|
|
for ( const def of Object.values(defs) ) {
|
|
|
|
if ( Array.isArray(def) ) {
|
|
|
|
for ( const layer of def ) {
|
|
|
|
if ( Array.isArray(layer) && layer.length > 1 && layer[0] === 'middleware::api:Permission' ) {
|
|
|
|
if ( typeof layer[1] === 'object' && layer[1].check ) {
|
|
|
|
scopes.push(layer[1].check)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
scopes.sort()
|
2020-05-21 02:17:07 +00:00
|
|
|
return scopes
|
|
|
|
}
|
|
|
|
|
|
|
|
async get_scopes(req, res, next) {
|
|
|
|
const scopes = this.api_scopes()
|
2020-05-17 04:55:08 +00:00
|
|
|
return res.api(scopes.map(x => {
|
|
|
|
return { scope: x }
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
async check_permissions(req, res, next) {
|
|
|
|
if ( !req.body.permissions )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(`${req.T('api.missing_field')} permissions`)
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
const parsed = typeof req.body.permissions === 'string' ? this.utility.infer(req.body.permissions) : req.body.permissions
|
|
|
|
const permissions = Array.isArray(parsed) ? parsed : [parsed]
|
|
|
|
|
|
|
|
const returns = {}
|
|
|
|
for ( const permission of permissions ) {
|
|
|
|
returns[permission] = req.user.can(permission)
|
|
|
|
}
|
|
|
|
|
|
|
|
return res.api(returns)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = exports = ReflectController
|