Files
memind/server/portal-wiki-routes.mjs

224 lines
4.4 KiB
JavaScript

import { parseCookies } from '../auth.mjs';
function wikiCookie(wikiAuth, token, secure) {
const parts = [
`${wikiAuth.COOKIE_NAME}=${encodeURIComponent(token)}`,
'Path=/',
'HttpOnly',
'SameSite=Lax',
'Max-Age=604800',
];
if (secure) parts.push('Secure');
return parts.join('; ');
}
function clearWikiCookie(wikiAuth, secure) {
const parts = [
`${wikiAuth.COOKIE_NAME}=`,
'Path=/',
'HttpOnly',
'SameSite=Lax',
'Max-Age=0',
];
if (secure) parts.push('Secure');
return parts.join('; ');
}
export function attachPortalWikiRoutes({
router,
jsonBody,
wikiAuth,
isSecureRequest,
parseCookiesFn = parseCookies,
} = {}) {
if (
!router ||
typeof jsonBody !== 'function' ||
!wikiAuth ||
typeof isSecureRequest !== 'function' ||
typeof parseCookiesFn !== 'function'
) {
throw new Error(
'attachPortalWikiRoutes requires route dependencies',
);
}
router.use(jsonBody);
router.post('/auth/register', (req, res) => {
const {
username,
password,
displayName,
} = req.body || {};
if (!username || !password) {
return res.status(400).json({
message: '用户名和密码不能为空',
});
}
const result = wikiAuth.register(
username,
password,
displayName,
);
if (!result.ok) {
return res.status(409).json({
message: result.message,
});
}
return res.json({
ok: true,
user: result.user,
});
});
router.post('/auth/login', (req, res) => {
const { username, password } = req.body || {};
if (!username || !password) {
return res.status(400).json({
message: '用户名和密码不能为空',
});
}
const result = wikiAuth.login(
username,
password,
);
if (!result.ok) {
return res.status(401).json({
message: result.message,
});
}
const secure = isSecureRequest(req);
res.set(
'Set-Cookie',
wikiCookie(wikiAuth, result.token, secure),
);
return res.json({
ok: true,
user: result.user,
});
});
router.post('/auth/logout', (req, res) => {
const cookies = parseCookiesFn(
req.get('cookie'),
);
wikiAuth.revoke(
cookies[wikiAuth.COOKIE_NAME],
);
res.set(
'Set-Cookie',
clearWikiCookie(
wikiAuth,
isSecureRequest(req),
),
);
return res.json({ ok: true });
});
router.get('/auth/me', (req, res) => {
const cookies = parseCookiesFn(
req.get('cookie'),
);
const session = wikiAuth.verify(
cookies[wikiAuth.COOKIE_NAME],
);
if (!session) {
return res.json({
authenticated: false,
user: null,
});
}
const user = wikiAuth.getUser(
session.username,
);
return res.json({
authenticated: true,
user,
});
});
function requireWikiAuth(req, res, next) {
const cookies = parseCookiesFn(
req.get('cookie'),
);
const session = wikiAuth.verify(
cookies[wikiAuth.COOKIE_NAME],
);
if (!session) {
return res.status(401).json({
message: '未登录',
});
}
req.wikiUser = session;
next();
}
router.get(
'/pages',
requireWikiAuth,
(req, res) => {
const { q } = req.query;
if (q) {
return res.json(
wikiAuth.searchPages(
req.wikiUser.username,
q,
),
);
}
res.json(
wikiAuth.listPages(
req.wikiUser.username,
),
);
},
);
router.get(
'/pages/:slug',
requireWikiAuth,
(req, res) => {
const page = wikiAuth.getPage(
req.wikiUser.username,
req.params.slug,
);
if (!page) {
return res.status(404).json({
message: '页面不存在',
});
}
res.json(page);
},
);
router.post(
'/pages/:slug',
requireWikiAuth,
(req, res) => {
const { title, content, tags } =
req.body || {};
const page = wikiAuth.savePage(
req.wikiUser.username,
req.params.slug,
title,
content,
tags,
);
res.json(page);
},
);
router.delete(
'/pages/:slug',
requireWikiAuth,
(req, res) => {
wikiAuth.deletePage(
req.wikiUser.username,
req.params.slug,
);
res.json({ ok: true });
},
);
}