diff --git a/lib/capability-discovery.js b/lib/capability-discovery.js new file mode 100644 index 000000000..0a347d61b --- /dev/null +++ b/lib/capability-discovery.js @@ -0,0 +1,68 @@ +'use strict' +/** + * @module capability-discovery + */ +const express = require('express') +const addLink = require('./header').addLink +const util = require('./utils') + +const serviceConfig = { + 'api': { + 'accounts': { + // 'changePassword': '/api/account/changePassword', + // 'delete': '/api/accounts/delete', + 'new': '/api/accounts/new', + 'recover': '/api/accounts/recover', + 'signin': '/api/accounts/signin', + 'signout': '/api/accounts/signout', + 'validateToken': '/api/accounts/validateToken' + } + } +} + +module.exports = capabilityDiscovery + +/** + * Returns a set of routes to deal with server capability discovery + * @method capabilityDiscovery + * @return {Router} Express router + */ +function capabilityDiscovery (corsSettings) { + var router = express.Router('/') + + // Advertise the server capability discover endpoint + router.options('*', serviceEndpointHeader) + router.get('/.well-known/solid', corsSettings, + serviceCapabilityDocument(serviceConfig)) + return router +} + +/** + * Handles advertising the server capability endpoint (adds a Link Relation + * header of type `service`, points to the capability document). + * To be used with OPTIONS requests. + * @method serviceEndpointHeader + * @param req + * @param res + * @param next + */ +function serviceEndpointHeader (req, res, next) { + let serviceEndpoint = `${util.uriBase(req)}/.well-known/solid` + addLink(res, serviceEndpoint, 'service') + next() +} + +/** + * Serves the service capability document (containing server root URL, including + * any base path the user specified in config, server API endpoints, etc). + * @method serviceCapabilityDocument + * @param req + * @param res + * @param next + */ +function serviceCapabilityDocument (serviceConfig) { + return (req, res, next) => { + serviceConfig.root = util.uriBase(req) // TODO make sure we align with the rest + res.json(serviceConfig) + } +} diff --git a/lib/create-app.js b/lib/create-app.js index 156bb3f4c..a0e3f8558 100644 --- a/lib/create-app.js +++ b/lib/create-app.js @@ -12,6 +12,7 @@ var vhost = require('vhost') var path = require('path') var EmailService = require('./email-service') const AccountRecovery = require('./account-recovery') +const capabilityDiscovery = require('./capability-discovery') var corsSettings = cors({ methods: [ @@ -76,6 +77,8 @@ function createApp (argv = {}) { next() }) + app.use('/', capabilityDiscovery(corsSettings)) + // Session app.use(session(sessionSettings)) diff --git a/test/capability-discovery.js b/test/capability-discovery.js new file mode 100644 index 000000000..30fd09a30 --- /dev/null +++ b/test/capability-discovery.js @@ -0,0 +1,40 @@ +var supertest = require('supertest') +var ldnode = require('../index') +var path = require('path') +var expect = require('chai').expect + +var ldpServer = ldnode.createServer({ + live: true, + root: path.join(__dirname, '/resources') +}) +var server = supertest(ldpServer) + +describe('Capability Discovery', function () { + describe('GET Service Capability document', function () { + it('should exist', function (done) { + server.get('/.well-known/solid') + .expect(200, done) + }) + it('should be a json file by default', function (done) { + server.get('/.well-known/solid') + .expect('content-type', /application\/json/) + .expect(200, done) + }) + it('includes a root element', function (done) { + server.get('/.well-known/solid') + .end(function (err, req) { + expect(req.body.root).to.exist + return done(err) + }) + }) + }) + + describe('OPTIONS API', function () { + it('should set the service Link header', + function (done) { + server.options('/') + .expect('Link', /<.*\.well-known\/solid>; rel="service"/) + .expect(204, done) + }) + }) +})