UNPKG

stackpress

Version:

Incept is a content management framework.

132 lines (131 loc) 4.94 kB
import { authorize, unauthorized, validData } from './helpers.js'; export default function plugin(ctx) { if (!ctx.config.get('api')) return; ctx.on('listen', (_req, _res, ctx) => { const { webhooks = [] } = ctx.config('api') || {}; for (const webhook of webhooks) { ctx.on(webhook.event, async (req, res) => { if (res.code !== 200) return; const data = webhook.data || {}; const params = req.data(); const results = res.toStatusResponse().results; if (!validData(webhook.validity, results)) return; await fetch(webhook.uri, { method: webhook.method, body: JSON.stringify({ data, params, results }), }); }, -200); } }); ctx.on('route', (_req, _res, ctx) => { const { endpoints = [] } = ctx.config('api') || {}; if (!Array.isArray(endpoints) || endpoints.length === 0) return; ctx.import.all('/auth/oauth/token', () => import('./pages/token.js')); ctx.import.all('/auth/oauth', () => import('./pages/oauth.js')); ctx.view.all('/auth/oauth', 'stackpress/esm/api/views/oauth', -100); for (const endpoint of endpoints) { cors(endpoint, ctx); if (endpoint.type === 'session') { session(endpoint, ctx); } else if (endpoint.type === 'app') { app(endpoint, ctx); } else if (endpoint.type === 'public') { open(endpoint, ctx); } } }); } ; export function cors(endpoint, ctx) { let origin = endpoint.cors === true ? '*' : endpoint.cors; if (typeof origin === 'string') { origin = [origin]; } if (!Array.isArray(origin)) return; const cors = function CrossOrigin(req, res) { if (origin.includes('*')) { res.headers.set('Access-Control-Allow-Origin', '*'); } else if (origin.includes(req.url.origin)) { res.headers.set('Access-Control-Allow-Origin', req.url.origin); } else { return; } const method = endpoint.method !== 'ALL' ? endpoint.method : '*'; res.headers.set('Access-Control-Request-Method', method); res.headers.set('Access-Control-Allow-Methods', 'OPTIONS, GET'); res.headers.set('Access-Control-Allow-Headers', '*'); }; const preflight = function PreFlight(req, res) { cors(req, res); res.code = 200; }; ctx.route('OPTIONS', endpoint.route, preflight, 1000); ctx.route(endpoint.method, endpoint.route, cors, 1000); } export function session(endpoint, ctx) { ctx.route(endpoint.method, endpoint.route, async function SessionAPI(req, res, ctx) { const authorization = authorize(req, res); if (!authorization) { return; } const { id, secret } = authorization; const response = await ctx.resolve('session-detail', { id }); if (!response || !response.results) { return unauthorized(res); } const session = response.results; if (req.method.toUpperCase() !== 'GET' && secret !== session.secret) { return unauthorized(res); } const permits = endpoint.scopes || []; if (!session.scopes.some(scope => permits.includes(scope))) { return unauthorized(res); } req.data.set(endpoint.data || {}); req.data.set('profileId', session.profileId); await ctx.emit(endpoint.event, req, res); }, endpoint.priority || 0); } ; export function app(endpoint, ctx) { ctx.route(endpoint.method, endpoint.route, async function AppAPI(req, res, ctx) { const authorization = authorize(req, res); if (!authorization) { return; } const { id, secret } = authorization; const response = await ctx.resolve('application-detail', { id }); if (!response || !response.results) { return unauthorized(res); } const application = response.results; if (req.method.toUpperCase() !== 'GET' && secret !== application.secret) { return unauthorized(res); } const permits = endpoint.scopes || []; if (!application.scopes.some(scope => permits.includes(scope))) { return unauthorized(res); } req.data.set(endpoint.data || {}); await ctx.emit(endpoint.event, req, res); }, endpoint.priority || 0); } ; export function open(endpoint, ctx) { ctx.route(endpoint.method, endpoint.route, async function PublicAPI(req, res, ctx) { req.data.set(endpoint.data || {}); await ctx.emit(endpoint.event, req, res); }, endpoint.priority || 0); } ;