const { Controller } = require('libflitter') const uuid = require('uuid/v4') class ReflectController extends Controller { static get services() { return [...super.services, 'routers', 'models'] } 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 }) let client_display = client && client.active ? client.name : '(Non-existent Client)' 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) .message('Token not found with that ID, or expired.') .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) .message('Missing required field: client_id') .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) .message('Invalid client_id.') .api() if ( !req.user.can(`oauth:client:${client.id}:view`) ) return res.status(401) .message('Insufficient permissions.') .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() 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) .message('Token not found with that ID, or expired.') .api() if ( !req.body.client_id ) return res.status(400) .message('Missing required field: client_id') .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) .message('Invalid client_id.') .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) .message('Token not found with that ID, or expired.') .api() await token.delete() return res.api() } api_scopes() { 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() return scopes } async get_scopes(req, res, next) { const scopes = this.api_scopes() return res.api(scopes.map(x => { return { scope: x } })) } async check_permissions(req, res, next) { if ( !req.body.permissions ) return res.status(400) .message('Missing permissions to check.') .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