224 lines
4.4 KiB
JavaScript
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 });
|
|
},
|
|
);
|
|
}
|