diff --git a/Dockerfile b/Dockerfile index b67baf8a8..f5b03017f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,4 +2,4 @@ FROM mhart/alpine-node:slim-10 WORKDIR /app COPY .build /app EXPOSE 8888 -CMD ["node", ".build/development.js"] +CMD ["node", ".build/app.js"] diff --git a/docker-compose.yml b/docker-compose.yml index 4aed184f2..89a4578f6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,11 +6,11 @@ services: links: - mongo volumes: - - ./config.yaml:/config/config.yaml + - ./data/config:/config ports: - 8888:8888 mongo: image: mongo:latest restart: always volumes: - - ./db:/data/db + - ./data/db:/data/db diff --git a/hydro/error.js b/hydro/error.js index e522028de..0a9263744 100644 --- a/hydro/error.js +++ b/hydro/error.js @@ -33,11 +33,11 @@ class HydroError extends Error { const UserFacingError = Err('UserFacingError', HydroError, 'UserFacingError', 400); const SystemError = Err('SystemError', HydroError, 'SystemError', 500); -const BadRequestError = Err('BadRequestError', UserFacingError, 400); -const ForbiddenError = Err('ForbiddenError', UserFacingError, 403); -const NotFoundError = Err('NotFoundError', UserFacingError, 404); -const MethodNotAllowedError = Err('MethodNotAllowedError', UserFacingError, 405); -const RemoteOnlineJudgeError = Err('RemoteOnlineJudgeError', UserFacingError, 500); +const BadRequestError = Err('BadRequestError', UserFacingError, 'BadRequestError', 400); +const ForbiddenError = Err('ForbiddenError', UserFacingError, 'ForbiddenError', 403); +const NotFoundError = Err('NotFoundError', UserFacingError, 'NotFoundError', 404); +const MethodNotAllowedError = Err('MethodNotAllowedError', UserFacingError, 'MethodNotAllowedError', 405); +const RemoteOnlineJudgeError = Err('RemoteOnlineJudgeError', UserFacingError, 'RemoteOnlineJudgeError', 500); const AlreadyVotedError = Err('AlreadyVotedError', ForbiddenError, "You've already voted."); const LoginError = Err('LoginError', ForbiddenError, 'Invalid password for user {0}.'); @@ -63,7 +63,7 @@ const ContestNotLiveError = Err('ContestNotLiveError', ForbiddenError, 'This con const ContestScoreboardHiddenError = Err('ContestScoreboardHiddenError', ForbiddenError, 'Contest scoreboard is not visible.'); const TrainingAlreadyEnrollError = Err('TrainingAlreadyEnrollError', ForbiddenError, "You've already enrolled this training."); const RoleAlreadyExistError = Err('RoleAlreadyExistError', ForbiddenError, 'This role already exists.'); -const CsrfTokenError = Err('CsrfTokenError', ForbiddenError); +const CsrfTokenError = Err('CsrfTokenError', ForbiddenError, 'CsrfTokenError'); const UserNotFoundError = Err('UserNotFoundError', NotFoundError, 'User {0} not found.'); const NoProblemError = Err('NoProblemError', NotFoundError, 'No problem.'); @@ -72,10 +72,10 @@ const ProblemDataNotFoundError = Err('ProblemDataNotFoundError', NotFoundError, const MessageNotFoundError = Err('MessageNotFoundError', NotFoundError, 'Message {0} not found.'); const DocumentNotFoundError = Err('DocumentNotFoundError', NotFoundError, 'Document {2} not found.'); -const ProblemNotFoundError = Err('ProblemNotFountError', DocumentNotFoundError, 'Problem {1} not found.'); -const SolutionNotFoundError = Err('SolutionNotFoundError', DocumentNotFoundError); -const TrainingNotFoundError = Err('TrainingNotFoundError', DocumentNotFoundError); -const ContestNotFoundError = Err('ContestNotFoundError', DocumentNotFoundError); +const ProblemNotFoundError = Err('ProblemNotFountError', DocumentNotFoundError, 'Problem {0} not found.'); +const SolutionNotFoundError = Err('SolutionNotFoundError', DocumentNotFoundError, 'Solution {0} not found.'); +const TrainingNotFoundError = Err('TrainingNotFoundError', DocumentNotFoundError, 'Training {0} not found.'); +const ContestNotFoundError = Err('ContestNotFoundError', DocumentNotFoundError, 'Contest {0} not found.'); const DiscussionNotFoundError = Err('DiscussionNotFoundError', DocumentNotFoundError, 'Discussion {0} not found.'); const DiscussionNodeNotFoundError = Err('DiscussionNodeNotFoundError', DocumentNotFoundError, 'Discussion node {1} not found.'); diff --git a/hydro/handler/user.js b/hydro/handler/user.js index 75794f010..e066ec77a 100644 --- a/hydro/handler/user.js +++ b/hydro/handler/user.js @@ -43,7 +43,7 @@ class UserLoginHandler extends Handler { await user.setById(udoc._id, { loginat: new Date(), loginip: this.request.ip }); if (udoc.priv === PRIV_NONE) throw new BlacklistedError(uname); this.session.uid = udoc._id; - this.session.rememberme = rememberme; + this.session.save = rememberme; this.response.redirect = this.request.referer.endsWith('/login') ? '/' : this.request.referer; } } diff --git a/hydro/model/token.js b/hydro/model/token.js index 8985b19aa..be86e18c0 100644 --- a/hydro/model/token.js +++ b/hydro/model/token.js @@ -28,7 +28,7 @@ async function add(tokenType, expireSeconds, data) { updateAt: now, expireAt: new Date(now.getTime() + expireSeconds * 1000), }); - return [str, res.ops]; + return [str, res.ops[0]]; } /** @@ -109,7 +109,7 @@ global.Hydro.model.token = module.exports = { get, update, del, - deleteByUid(uid) { + delByUid(uid) { return coll.deleteMany({ uid }); }, getMostRecentSessionByUid(uid) { diff --git a/hydro/service/server.js b/hydro/service/server.js index d9c04b409..53300e5d9 100644 --- a/hydro/service/server.js +++ b/hydro/service/server.js @@ -234,7 +234,6 @@ const Handler = HandlerMixin(class { cdn_prefix: '/', url_prefix: '/', }; - this._handler = {}; this.session = {}; } @@ -255,34 +254,37 @@ const Handler = HandlerMixin(class { this.response.disposition = `attachment; filename="${name}"`; } - async init({ domainId }) { - this.response.body = {}; - this.now = new Date(); - this._handler.sid = this.request.cookies.get('sid'); - this._handler.save = this.request.cookies.get('save'); - if (this._handler.save) this._handler.expireSeconds = await system.get('session.saved_expire_seconds'); - else this._handler.expireSeconds = await system.get('session.unsaved_expire_seconds'); - this.session = this._handler.sid - ? await token.update( - this._handler.sid, - token.TYPE_SESSION, - this._handler.expireSeconds, - { - updateIp: this.request.ip, - updateUa: this.request.headers['user-agent'] || '', - }, - ) : { uid: 1 }; + async getSession() { + const sid = this.request.cookies.get('sid'); + this.session = await token.get(sid, token.TYPE_SESSION, false); if (!this.session) this.session = { uid: 0 }; + } + + async getBdoc() { const bdoc = await blacklist.get(this.request.ip); if (bdoc) throw new BlacklistedError(this.request.ip); - this.user = await user.getById(domainId, this.session.uid); - if (!this.user) throw new UserNotFoundError(this.session.uid); + } + + async getCsrfToken() { this.csrfToken = await token.createOrUpdate(token.TYPE_CSRF_TOKEN, 600, { path: this.request.path, uid: this.session.uid, }); this.UIContext.csrfToken = this.csrfToken; + } + + async init({ domainId }) { + this.response.body = {}; + this.now = new Date(); this.preferJson = (this.request.headers.accept || '').includes('application/json'); + await Promise.all([ + this.getSession(), + this.getBdoc(), + ]); + [this.user] = await Promise.all([ + user.getById(domainId, this.session.uid, true), + this.getCsrfToken(), + ]); } async checkCsrfToken(csrfToken) { @@ -339,31 +341,37 @@ const Handler = HandlerMixin(class { } async saveCookie() { + const expireSeconds = this.session.save + ? await system.get('session.expire_seconds') + : await system.get('session.unsaved_expire_seconds'); if (this.session._id) { await token.update( this.session._id, token.TYPE_SESSION, - this._handler.expireSeconds, - this.session, + expireSeconds, + { + ...this.session, + updateIp: this.request.ip, + updateUa: this.request.headers['user-agent'] || '', + }, ); } else { - [this.session._id] = await token.add( + [, this.session] = await token.add( token.TYPE_SESSION, - this._handler.expireSeconds, + expireSeconds, { + ...this.session, createIp: this.request.ip, createUa: this.request.headers['user-agent'] || '', updateIp: this.request.ip, updateUa: this.request.headers['user-agent'] || '', - ...this.session, }, ); } const cookie = { secure: await system.get('session.secure') }; - if (this._handler.save) { + if (this.session.save) { cookie.expires = this.session.expireAt; - cookie.maxAge = this._handler.expireSeconds; - this.ctx.cookies.set('save', 'true', cookie); + cookie.maxAge = expireSeconds; } this.ctx.cookies.set('sid', this.session._id, cookie); } diff --git a/templates/user_login.html b/templates/user_login.html index 3a001b3dd..4f684f181 100644 --- a/templates/user_login.html +++ b/templates/user_login.html @@ -33,6 +33,7 @@ {% endif %}