eslint fixes as well as fixing a small variable typo

This commit is contained in:
Nathan Byrd 2023-01-07 13:40:52 -06:00
parent 23f753e4b3
commit 9eb3a1d37f
2 changed files with 211 additions and 215 deletions

View File

@ -8,12 +8,10 @@ const {
DefaultProfileTemplate, DefaultProfileTemplate,
} = require('../../../activitypub_util'); } = require('../../../activitypub_util');
const UserProps = require('../../../user_property'); const UserProps = require('../../../user_property');
const { Errors } = require('../../../enig_error');
const Config = require('../../../config').get; const Config = require('../../../config').get;
// deps // deps
const _ = require('lodash'); const _ = require('lodash');
const { trim } = require('lodash');
const enigma_assert = require('../../../enigma_assert'); const enigma_assert = require('../../../enigma_assert');
exports.moduleInfo = { exports.moduleInfo = {
@ -59,7 +57,7 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
userFromAccount(accountName, (err, user) => { userFromAccount(accountName, (err, user) => {
if (err) { if (err) {
this.log.info( this.log.info(
{ reason: error.message, accountName: accountName }, { reason: err.message, accountName: accountName },
`No user "${accountName}" for "self"` `No user "${accountName}" for "self"`
); );
return this._notFound(resp); return this._notFound(resp);

View File

@ -3,242 +3,240 @@ const Config = require('../../../config').get;
const { Errors } = require('../../../enig_error'); const { Errors } = require('../../../enig_error');
const { WellKnownLocations } = require('../web'); const { WellKnownLocations } = require('../web');
const { const {
selfUrl, selfUrl,
webFingerProfileUrl, webFingerProfileUrl,
userFromAccount, userFromAccount,
getUserProfileTemplatedBody, getUserProfileTemplatedBody,
DefaultProfileTemplate, DefaultProfileTemplate,
} = require('../../../activitypub_util'); } = require('../../../activitypub_util');
const _ = require('lodash'); const _ = require('lodash');
const enigma_assert = require('../../../enigma_assert'); const enigma_assert = require('../../../enigma_assert');
exports.moduleInfo = { exports.moduleInfo = {
name: 'WebFinger', name: 'WebFinger',
desc: 'A simple WebFinger Handler.', desc: 'A simple WebFinger Handler.',
author: 'NuSkooler, CognitiveGears', author: 'NuSkooler, CognitiveGears',
packageName: 'codes.l33t.enigma.web.handler.webfinger', packageName: 'codes.l33t.enigma.web.handler.webfinger',
}; };
// //
// WebFinger: https://www.rfc-editor.org/rfc/rfc7033 // WebFinger: https://www.rfc-editor.org/rfc/rfc7033
// //
exports.getModule = class WebFingerWebHandler extends WebHandlerModule { exports.getModule = class WebFingerWebHandler extends WebHandlerModule {
constructor() { constructor() {
super(); super();
}
init(webServer, cb) {
// we rely on the web server
this.webServer = webServer;
enigma_assert(webServer, 'WebFinger Web Handler init without webServer');
this.log = webServer.logger().child({ webHandler: 'WebFinger' });
const domain = this.webServer.getDomain();
if (!domain) {
return cb(Errors.UnexpectedState('Web server does not have "domain" set'));
} }
init(webServer, cb) { this.acceptedResourceRegExps = [
const config = Config(); // acct:NAME@our.domain.tld
// https://www.rfc-editor.org/rfc/rfc7565
new RegExp(`^acct:(.+)@${domain}$`),
// profile page
// https://webfinger.net/rel/profile-page/
new RegExp(
`^${this.webServer.buildUrl(WellKnownLocations.Internal + '/wf/@')}(.+)$`
),
// self URL
new RegExp(
`^${this.webServer.buildUrl(
WellKnownLocations.Internal + '/ap/users/'
)}(.+)$`
),
];
// we rely on the web server this.webServer.addRoute({
this.webServer = webServer; method: 'GET',
enigma_assert(webServer, 'WebFinger Web Handler init without webServer'); // https://www.rfc-editor.org/rfc/rfc7033.html#section-10.1
path: /^\/\.well-known\/webfinger\/?\?/,
handler: this._webFingerRequestHandler.bind(this),
});
this.log = webServer.logger().child({ webHandler: 'WebFinger' }); this.webServer.addRoute({
method: 'GET',
path: /^\/_enig\/wf\/@.+$/,
handler: this._profileRequestHandler.bind(this),
});
const domain = this.webServer.getDomain(); return cb(null);
if (!domain) { }
return cb(Errors.UnexpectedState('Web server does not have "domain" set'));
}
this.acceptedResourceRegExps = [ _profileRequestHandler(req, resp) {
// acct:NAME@our.domain.tld const url = new URL(req.url, `https://${req.headers.host}`);
// https://www.rfc-editor.org/rfc/rfc7565
new RegExp(`^acct:(.+)@${domain}$`),
// profile page
// https://webfinger.net/rel/profile-page/
new RegExp(
`^${this.webServer.buildUrl(WellKnownLocations.Internal + '/wf/@')}(.+)$`
),
// self URL
new RegExp(
`^${this.webServer.buildUrl(
WellKnownLocations.Internal + '/ap/users/'
)}(.+)$`
),
];
this.webServer.addRoute({ const resource = url.pathname;
method: 'GET', if (_.isEmpty(resource)) {
// https://www.rfc-editor.org/rfc/rfc7033.html#section-10.1 return this.webServer.instance.respondWithError(
path: /^\/\.well-known\/webfinger\/?\?/, resp,
handler: this._webFingerRequestHandler.bind(this), 400,
}); 'pathname is required',
'Missing "resource"'
this.webServer.addRoute({ );
method: 'GET',
path: /^\/_enig\/wf\/@.+$/,
handler: this._profileRequestHandler.bind(this),
});
return cb(null);
} }
_profileRequestHandler(req, resp) { const userPosition = resource.indexOf('@');
const url = new URL(req.url, `https://${req.headers.host}`); if (-1 == userPosition || userPosition == resource.length - 1) {
this._notFound(resp);
const resource = url.pathname; return Errors.DoesNotExist('"@username" missing from path');
if (_.isEmpty(resource)) {
return this.webServer.instance.respondWithError(
resp,
400,
'pathname is required',
'Missing "resource"'
);
}
const userPosition = resource.indexOf('@');
if (-1 == userPosition || userPosition == resource.length - 1) {
this._notFound(resp);
return Errors.DoesNotExist('"@username" missing from path');
}
const accountName = resource.substring(userPosition + 1);
userFromAccount(accountName, (err, user) => {
if (err) {
this.log.warn(
{ url: req.url, error: err.message, type: 'Profile' },
`No profile for "${accountName}" could be retrieved`
);
return this._notFound(resp);
}
let templateFile = _.get(
Config(),
'contentServers.web.handlers.webFinger.profileTemplate'
);
if (templateFile) {
templateFile = this.webServer.resolveTemplatePath(templateFile);
}
getUserProfileTemplatedBody(
templateFile,
user,
DefaultProfileTemplate,
'text/plain',
(err, body, contentType) => {
if (err) {
return this._notFound(resp);
}
const headers = {
'Content-Type': contentType,
'Content-Length': body.length,
};
resp.writeHead(200, headers);
return resp.end(body);
}
);
});
} }
_webFingerRequestHandler(req, resp) { const accountName = resource.substring(userPosition + 1);
const url = new URL(req.url, `https://${req.headers.host}`);
const resource = url.searchParams.get('resource'); userFromAccount(accountName, (err, user) => {
if (!resource) { if (err) {
return this.webServer.respondWithError( this.log.warn(
resp, { url: req.url, error: err.message, type: 'Profile' },
400, `No profile for "${accountName}" could be retrieved`
'"resource" is required',
'Missing "resource"'
);
}
const accountName = this._getAccountName(resource);
if (!accountName || accountName.length < 1) {
this._notFound(resp);
return Errors.DoesNotExist(
`Failed to parse "account name" for resource: ${resource}`
);
}
userFromAccount(accountName, (err, user) => {
if (err) {
this.log.warn(
{ url: req.url, error: err.message, type: 'WebFinger' },
`No account for "${accountName}" could be retrieved`
);
return this._notFound(resp);
}
const domain = this.webServer.getDomain();
const body = JSON.stringify({
subject: `acct:${user.username}@${domain}`,
aliases: [this._profileUrl(user), this._selfUrl(user)],
links: [
this._profilePageLink(user),
this._selfLink(user),
this._subscribeLink(),
],
});
const headers = {
'Content-Type': 'application/jrd+json',
'Content-Length': body.length,
};
resp.writeHead(200, headers);
return resp.end(body);
});
}
_profileUrl(user) {
return webFingerProfileUrl(this.webServer, user);
}
_profilePageLink(user) {
const href = this._profileUrl(user);
return {
rel: 'http://webfinger.net/rel/profile-page',
type: 'text/plain',
href,
};
}
_selfUrl(user) {
return selfUrl(this.webServer, user);
}
// :TODO: only if ActivityPub is enabled
_selfLink(user) {
const href = this._selfUrl(user);
return {
rel: 'self',
type: 'application/activity+json',
href,
};
}
// :TODO: only if ActivityPub is enabled
_subscribeLink() {
return {
rel: 'http://ostatus.org/schema/1.0/subscribe',
template: this.webServer.buildUrl(
WellKnownLocations.Internal + '/ap/authorize_interaction?uri={uri}'
),
};
}
_getAccountName(resource) {
for (const re of this.acceptedResourceRegExps) {
const m = resource.match(re);
if (m && m.length === 2) {
return m[1];
}
}
}
_notFound(resp) {
this.webServer.respondWithError(
resp,
404,
'Resource not found',
'Resource Not Found'
); );
return this._notFound(resp);
}
let templateFile = _.get(
Config(),
'contentServers.web.handlers.webFinger.profileTemplate'
);
if (templateFile) {
templateFile = this.webServer.resolveTemplatePath(templateFile);
}
getUserProfileTemplatedBody(
templateFile,
user,
DefaultProfileTemplate,
'text/plain',
(err, body, contentType) => {
if (err) {
return this._notFound(resp);
}
const headers = {
'Content-Type': contentType,
'Content-Length': body.length,
};
resp.writeHead(200, headers);
return resp.end(body);
}
);
});
}
_webFingerRequestHandler(req, resp) {
const url = new URL(req.url, `https://${req.headers.host}`);
const resource = url.searchParams.get('resource');
if (!resource) {
return this.webServer.respondWithError(
resp,
400,
'"resource" is required',
'Missing "resource"'
);
} }
const accountName = this._getAccountName(resource);
if (!accountName || accountName.length < 1) {
this._notFound(resp);
return Errors.DoesNotExist(
`Failed to parse "account name" for resource: ${resource}`
);
}
userFromAccount(accountName, (err, user) => {
if (err) {
this.log.warn(
{ url: req.url, error: err.message, type: 'WebFinger' },
`No account for "${accountName}" could be retrieved`
);
return this._notFound(resp);
}
const domain = this.webServer.getDomain();
const body = JSON.stringify({
subject: `acct:${user.username}@${domain}`,
aliases: [this._profileUrl(user), this._selfUrl(user)],
links: [
this._profilePageLink(user),
this._selfLink(user),
this._subscribeLink(),
],
});
const headers = {
'Content-Type': 'application/jrd+json',
'Content-Length': body.length,
};
resp.writeHead(200, headers);
return resp.end(body);
});
}
_profileUrl(user) {
return webFingerProfileUrl(this.webServer, user);
}
_profilePageLink(user) {
const href = this._profileUrl(user);
return {
rel: 'http://webfinger.net/rel/profile-page',
type: 'text/plain',
href,
};
}
_selfUrl(user) {
return selfUrl(this.webServer, user);
}
// :TODO: only if ActivityPub is enabled
_selfLink(user) {
const href = this._selfUrl(user);
return {
rel: 'self',
type: 'application/activity+json',
href,
};
}
// :TODO: only if ActivityPub is enabled
_subscribeLink() {
return {
rel: 'http://ostatus.org/schema/1.0/subscribe',
template: this.webServer.buildUrl(
WellKnownLocations.Internal + '/ap/authorize_interaction?uri={uri}'
),
};
}
_getAccountName(resource) {
for (const re of this.acceptedResourceRegExps) {
const m = resource.match(re);
if (m && m.length === 2) {
return m[1];
}
}
}
_notFound(resp) {
this.webServer.respondWithError(
resp,
404,
'Resource not found',
'Resource Not Found'
);
}
}; };