summaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorAcid Chicken (硫酸鶏) <root@acid-chicken.com>2019-02-05 17:42:55 +0900
committerGitHub <noreply@github.com>2019-02-05 17:42:55 +0900
commit9dd06a7621d1745b30ed1c2b1d94d34143dd638e (patch)
tree7531db8f03407cc4b9106c36b2b5ab3dadf7672a /src/server
parentMerge branch 'develop' of https://github.com/syuilo/misskey into develop (diff)
downloadsharkey-9dd06a7621d1745b30ed1c2b1d94d34143dd638e.tar.gz
sharkey-9dd06a7621d1745b30ed1c2b1d94d34143dd638e.tar.bz2
sharkey-9dd06a7621d1745b30ed1c2b1d94d34143dd638e.zip
/.well-known 周りをいい感じに (#4141)
* Enhance /.well-known and their friends * Fix bug
Diffstat (limited to 'src/server')
-rw-r--r--src/server/index.ts11
-rw-r--r--src/server/nodeinfo.ts73
-rw-r--r--src/server/webfinger.ts75
-rw-r--r--src/server/well-known.ts102
4 files changed, 179 insertions, 82 deletions
diff --git a/src/server/index.ts b/src/server/index.ts
index 720a191d55..0e1c701050 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -16,7 +16,8 @@ import * as requestStats from 'request-stats';
import * as slow from 'koa-slow';
import activityPub from './activitypub';
-import webFinger from './webfinger';
+import nodeinfo from './nodeinfo';
+import wellKnown from './well-known';
import config from '../config';
import networkChart from '../chart/network';
import apiServer from './api';
@@ -68,7 +69,8 @@ const router = new Router();
// Routing
router.use(activityPub.routes());
-router.use(webFinger.routes());
+router.use(nodeinfo.routes());
+router.use(wellKnown.routes());
router.get('/verify-email/:code', async ctx => {
const user = await User.findOne({ emailVerifyCode: ctx.params.code });
@@ -88,11 +90,6 @@ router.get('/verify-email/:code', async ctx => {
}
});
-// Return 404 for other .well-known
-router.all('/.well-known/*', async ctx => {
- ctx.status = 404;
-});
-
// Register router
app.use(router.routes());
diff --git a/src/server/nodeinfo.ts b/src/server/nodeinfo.ts
new file mode 100644
index 0000000000..5abb2e4973
--- /dev/null
+++ b/src/server/nodeinfo.ts
@@ -0,0 +1,73 @@
+import * as Router from 'koa-router';
+import config from '../config';
+import fetchMeta from '../misc/fetch-meta';
+import User from '../models/user';
+import { name as softwareName, version, repository } from '../../package.json';
+import Note from '../models/note';
+
+const router = new Router();
+
+const nodeinfo2_1path = '/nodeinfo/2.1';
+const nodeinfo2_0path = '/nodeinfo/2.0';
+
+export const links = [/* (awaiting release) {
+ rel: 'http://nodeinfo.diaspora.software/ns/schema/2.1',
+ href: config.url + nodeinfo2_1path
+}, */{
+ rel: 'http://nodeinfo.diaspora.software/ns/schema/2.0',
+ href: config.url + nodeinfo2_0path
+}];
+
+const nodeinfo2 = async () => {
+ const [
+ { name, description, maintainer, langs, broadcasts, disableRegistration, disableLocalTimeline, disableGlobalTimeline, enableRecaptcha, maxNoteTextLength, enableTwitterIntegration, enableGithubIntegration, enableDiscordIntegration, enableEmail, enableServiceWorker },
+ total,
+ activeHalfyear,
+ activeMonth,
+ localPosts,
+ localComments
+ ] = await Promise.all([
+ fetchMeta(),
+ User.count({ host: null }),
+ User.count({ host: null, updatedAt: { $gt: new Date(Date.now() - 15552000000) } }),
+ User.count({ host: null, updatedAt: { $gt: new Date(Date.now() - 2592000000) } }),
+ Note.count({ '_user.host': null, replyId: null }),
+ Note.count({ '_user.host': null, replyId: { $ne: null } })
+ ]);
+
+ return {
+ software: {
+ name: softwareName,
+ version,
+ repository: repository.url
+ },
+ protocols: ['activitypub'],
+ services: {
+ inbound: [] as string[],
+ outbound: ['atom1.0', 'rss2.0']
+ },
+ openRegistrations: !disableRegistration,
+ usage: {
+ users: { total, activeHalfyear, activeMonth },
+ localPosts,
+ localComments
+ },
+ metadata: { name, description, maintainer, langs, broadcasts, disableRegistration, disableLocalTimeline, disableGlobalTimeline, enableRecaptcha, maxNoteTextLength, enableTwitterIntegration, enableGithubIntegration, enableDiscordIntegration, enableEmail, enableServiceWorker }
+ };
+};
+
+router.get(nodeinfo2_1path, async ctx => {
+ const base = await nodeinfo2();
+
+ ctx.body = { version: '2.1', ...base };
+});
+
+router.get(nodeinfo2_0path, async ctx => {
+ const base = await nodeinfo2();
+
+ delete base.software.repository;
+
+ ctx.body = { version: '2.0', ...base };
+});
+
+export default router;
diff --git a/src/server/webfinger.ts b/src/server/webfinger.ts
deleted file mode 100644
index 0f3e53b60f..0000000000
--- a/src/server/webfinger.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import * as mongo from 'mongodb';
-import * as Router from 'koa-router';
-
-import config from '../config';
-import parseAcct from '../misc/acct/parse';
-import User, { IUser } from '../models/user';
-
-// Init router
-const router = new Router();
-
-router.get('/.well-known/webfinger', async ctx => {
- if (typeof ctx.query.resource !== 'string') {
- ctx.status = 400;
- return;
- }
-
- const resourceLower = ctx.query.resource.toLowerCase();
- let acctLower;
- let id;
-
- if (resourceLower.startsWith(config.url.toLowerCase() + '/@')) {
- acctLower = resourceLower.split('/').pop();
- } else if (resourceLower.startsWith(config.url.toLowerCase() + '/users/')) {
- id = new mongo.ObjectID(resourceLower.split('/').pop());
- } else if (resourceLower.startsWith('acct:')) {
- acctLower = resourceLower.slice('acct:'.length);
- } else {
- acctLower = resourceLower;
- }
-
- let user: IUser;
-
- if (acctLower) {
- const parsedAcctLower = parseAcct(acctLower);
- if (![null, config.host.toLowerCase()].includes(parsedAcctLower.host)) {
- ctx.status = 422;
- return;
- }
-
- user = await User.findOne({
- usernameLower: parsedAcctLower.username,
- host: null
- });
- } else {
- user = await User.findOne({
- _id: id,
- host: null
- });
- }
-
- if (user === null) {
- ctx.status = 404;
- return;
- }
-
- ctx.body = {
- subject: `acct:${user.username}@${config.host}`,
- links: [{
- rel: 'self',
- type: 'application/activity+json',
- href: `${config.url}/users/${user._id}`
- }, {
- rel: 'http://webfinger.net/rel/profile-page',
- type: 'text/html',
- href: `${config.url}/@${user.username}`
- }, {
- rel: 'http://ostatus.org/schema/1.0/subscribe',
- template: `${config.url}/authorize-follow?acct={uri}`
- }]
- };
-
- ctx.set('Cache-Control', 'public, max-age=180');
-});
-
-export default router;
diff --git a/src/server/well-known.ts b/src/server/well-known.ts
new file mode 100644
index 0000000000..3c994793e1
--- /dev/null
+++ b/src/server/well-known.ts
@@ -0,0 +1,102 @@
+import * as mongo from 'mongodb';
+import * as Router from 'koa-router';
+
+import config from '../config';
+import parseAcct from '../misc/acct/parse';
+import User from '../models/user';
+import Acct from '../misc/acct/type';
+import { links } from './nodeinfo';
+
+// Init router
+const router = new Router();
+
+const webFingerPath = '/.well-known/webfinger';
+
+router.get('/.well-known/host-meta', async ctx => {
+ ctx.set('Content-Type', 'application/xrd+xml');
+ ctx.body = `<?xml version="1.0" encoding="UTF-8"?>
+<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
+ <Link rel="lrdd" type="application/xrd+xml" template="${config.url}${webFingerPath}?resource={uri}"/>
+</XRD>
+`;
+});
+
+router.get('/.well-known/host-meta.json', async ctx => {
+ ctx.set('Content-Type', 'application/jrd+json');
+ ctx.body = {
+ links: [{
+ rel: 'lrdd',
+ type: 'application/xrd+xml',
+ template: `${config.url}${webFingerPath}?resource={uri}`
+ }]
+ };
+});
+
+router.get('/.well-known/nodeinfo', async ctx => {
+ ctx.body = { links };
+});
+
+router.get(webFingerPath, async ctx => {
+ const generateQuery = (resource: string) =>
+ resource.startsWith(`${config.url.toLowerCase()}/users/`) ?
+ fromId(new mongo.ObjectID(resource.split('/').pop())) :
+ fromAcct(parseAcct(
+ resource.startsWith(`${config.url.toLowerCase()}/@`) ? resource.split('/').pop() :
+ resource.startsWith('acct:') ? resource.slice('acct:'.length) :
+ resource));
+
+ const fromId = (_id: mongo.ObjectID): Record<string, any> => ({
+ _id,
+ host: null
+ });
+
+ const fromAcct = (acct: Acct): Record<string, any> | number =>
+ !acct.host || acct.host === config.host.toLowerCase() ? {
+ usernameLower: acct.username,
+ host: null
+ } : 422;
+
+ if (typeof ctx.query.resource !== 'string') {
+ ctx.status = 400;
+ return;
+ }
+
+ const query = generateQuery(ctx.query.resource.toLowerCase());
+
+ if (typeof query === 'number') {
+ ctx.status = query;
+ return;
+ }
+
+ const user = await User.findOne(query);
+
+ if (user === null) {
+ ctx.status = 404;
+ return;
+ }
+
+ ctx.body = {
+ subject: `acct:${user.username}@${config.host}`,
+ links: [{
+ rel: 'self',
+ type: 'application/activity+json',
+ href: `${config.url}/users/${user._id}`
+ }, {
+ rel: 'http://webfinger.net/rel/profile-page',
+ type: 'text/html',
+ href: `${config.url}/@${user.username}`
+ }, {
+ rel: 'http://ostatus.org/schema/1.0/subscribe',
+ template: `${config.url}/authorize-follow?acct={uri}`
+ }]
+ };
+
+ ctx.set('Cache-Control', 'public, max-age=180');
+});
+
+// Return 404 for other .well-known
+router.all('/.well-known/*', async ctx => {
+ ctx.status = 404;
+});
+
+export default router;