some bug fix

This commit is contained in:
undefined committed 2020-07-03 22:54:07 +08:00
1 parent 57f711ed4f
commit fb5c29226b
11 files changed
+57 -44

No files matched your search

+1 -1
View File
@@ -2,4 +2,4 @@ FROM mhart/alpine-node:slim-10
WORKDIR /app WORKDIR /app
COPY .build /app COPY .build /app
EXPOSE 8888 EXPOSE 8888
CMD ["node", ".build/development.js"] CMD ["node", ".build/app.js"]
+2 -2
View File
@@ -6,11 +6,11 @@ services:
links: links:
- mongo - mongo
volumes: volumes:
- ./config.yaml:/config/config.yaml - ./data/config:/config
ports: ports:
- 8888:8888 - 8888:8888
mongo: mongo:
image: mongo:latest image: mongo:latest
restart: always restart: always
volumes: volumes:
- ./db:/data/db - ./data/db:/data/db
+10 -10
View File
@@ -33,11 +33,11 @@ class HydroError extends Error {
const UserFacingError = Err('UserFacingError', HydroError, 'UserFacingError', 400); const UserFacingError = Err('UserFacingError', HydroError, 'UserFacingError', 400);
const SystemError = Err('SystemError', HydroError, 'SystemError', 500); const SystemError = Err('SystemError', HydroError, 'SystemError', 500);
const BadRequestError = Err('BadRequestError', UserFacingError, 400); const BadRequestError = Err('BadRequestError', UserFacingError, 'BadRequestError', 400);
const ForbiddenError = Err('ForbiddenError', UserFacingError, 403); const ForbiddenError = Err('ForbiddenError', UserFacingError, 'ForbiddenError', 403);
const NotFoundError = Err('NotFoundError', UserFacingError, 404); const NotFoundError = Err('NotFoundError', UserFacingError, 'NotFoundError', 404);
const MethodNotAllowedError = Err('MethodNotAllowedError', UserFacingError, 405); const MethodNotAllowedError = Err('MethodNotAllowedError', UserFacingError, 'MethodNotAllowedError', 405);
const RemoteOnlineJudgeError = Err('RemoteOnlineJudgeError', UserFacingError, 500); const RemoteOnlineJudgeError = Err('RemoteOnlineJudgeError', UserFacingError, 'RemoteOnlineJudgeError', 500);
const AlreadyVotedError = Err('AlreadyVotedError', ForbiddenError, "You've already voted."); const AlreadyVotedError = Err('AlreadyVotedError', ForbiddenError, "You've already voted.");
const LoginError = Err('LoginError', ForbiddenError, 'Invalid password for user {0}.'); 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 ContestScoreboardHiddenError = Err('ContestScoreboardHiddenError', ForbiddenError, 'Contest scoreboard is not visible.');
const TrainingAlreadyEnrollError = Err('TrainingAlreadyEnrollError', ForbiddenError, "You've already enrolled this training."); const TrainingAlreadyEnrollError = Err('TrainingAlreadyEnrollError', ForbiddenError, "You've already enrolled this training.");
const RoleAlreadyExistError = Err('RoleAlreadyExistError', ForbiddenError, 'This role already exists.'); 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 UserNotFoundError = Err('UserNotFoundError', NotFoundError, 'User {0} not found.');
const NoProblemError = Err('NoProblemError', NotFoundError, 'No problem.'); 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 MessageNotFoundError = Err('MessageNotFoundError', NotFoundError, 'Message {0} not found.');
const DocumentNotFoundError = Err('DocumentNotFoundError', NotFoundError, 'Document {2} not found.'); const DocumentNotFoundError = Err('DocumentNotFoundError', NotFoundError, 'Document {2} not found.');
const ProblemNotFoundError = Err('ProblemNotFountError', DocumentNotFoundError, 'Problem {1} not found.'); const ProblemNotFoundError = Err('ProblemNotFountError', DocumentNotFoundError, 'Problem {0} not found.');
const SolutionNotFoundError = Err('SolutionNotFoundError', DocumentNotFoundError); const SolutionNotFoundError = Err('SolutionNotFoundError', DocumentNotFoundError, 'Solution {0} not found.');
const TrainingNotFoundError = Err('TrainingNotFoundError', DocumentNotFoundError); const TrainingNotFoundError = Err('TrainingNotFoundError', DocumentNotFoundError, 'Training {0} not found.');
const ContestNotFoundError = Err('ContestNotFoundError', DocumentNotFoundError); const ContestNotFoundError = Err('ContestNotFoundError', DocumentNotFoundError, 'Contest {0} not found.');
const DiscussionNotFoundError = Err('DiscussionNotFoundError', DocumentNotFoundError, 'Discussion {0} not found.'); const DiscussionNotFoundError = Err('DiscussionNotFoundError', DocumentNotFoundError, 'Discussion {0} not found.');
const DiscussionNodeNotFoundError = Err('DiscussionNodeNotFoundError', DocumentNotFoundError, 'Discussion node {1} not found.'); const DiscussionNodeNotFoundError = Err('DiscussionNodeNotFoundError', DocumentNotFoundError, 'Discussion node {1} not found.');
+1 -1
View File
@@ -43,7 +43,7 @@ class UserLoginHandler extends Handler {
await user.setById(udoc._id, { loginat: new Date(), loginip: this.request.ip }); await user.setById(udoc._id, { loginat: new Date(), loginip: this.request.ip });
if (udoc.priv === PRIV_NONE) throw new BlacklistedError(uname); if (udoc.priv === PRIV_NONE) throw new BlacklistedError(uname);
this.session.uid = udoc._id; this.session.uid = udoc._id;
this.session.rememberme = rememberme; this.session.save = rememberme;
this.response.redirect = this.request.referer.endsWith('/login') ? '/' : this.request.referer; this.response.redirect = this.request.referer.endsWith('/login') ? '/' : this.request.referer;
} }
} }
+2 -2
View File
@@ -28,7 +28,7 @@ async function add(tokenType, expireSeconds, data) {
updateAt: now, updateAt: now,
expireAt: new Date(now.getTime() + expireSeconds * 1000), 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, get,
update, update,
del, del,
deleteByUid(uid) { delByUid(uid) {
return coll.deleteMany({ uid }); return coll.deleteMany({ uid });
}, },
getMostRecentSessionByUid(uid) { getMostRecentSessionByUid(uid) {
+36 -28
View File
@@ -234,7 +234,6 @@ const Handler = HandlerMixin(class {
cdn_prefix: '/', cdn_prefix: '/',
url_prefix: '/', url_prefix: '/',
}; };
this._handler = {};
this.session = {}; this.session = {};
} }
@@ -255,34 +254,37 @@ const Handler = HandlerMixin(class {
this.response.disposition = `attachment; filename="${name}"`; this.response.disposition = `attachment; filename="${name}"`;
} }
async init({ domainId }) { async getSession() {
this.response.body = {}; const sid = this.request.cookies.get('sid');
this.now = new Date(); this.session = await token.get(sid, token.TYPE_SESSION, false);
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 };
if (!this.session) this.session = { uid: 0 }; if (!this.session) this.session = { uid: 0 };
}
async getBdoc() {
const bdoc = await blacklist.get(this.request.ip); const bdoc = await blacklist.get(this.request.ip);
if (bdoc) throw new BlacklistedError(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, { this.csrfToken = await token.createOrUpdate(token.TYPE_CSRF_TOKEN, 600, {
path: this.request.path, path: this.request.path,
uid: this.session.uid, uid: this.session.uid,
}); });
this.UIContext.csrfToken = this.csrfToken; this.UIContext.csrfToken = this.csrfToken;
}
async init({ domainId }) {
this.response.body = {};
this.now = new Date();
this.preferJson = (this.request.headers.accept || '').includes('application/json'); 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) { async checkCsrfToken(csrfToken) {
@@ -339,31 +341,37 @@ const Handler = HandlerMixin(class {
} }
async saveCookie() { async saveCookie() {
const expireSeconds = this.session.save
? await system.get('session.expire_seconds')
: await system.get('session.unsaved_expire_seconds');
if (this.session._id) { if (this.session._id) {
await token.update( await token.update(
this.session._id, this.session._id,
token.TYPE_SESSION, token.TYPE_SESSION,
this._handler.expireSeconds, expireSeconds,
this.session, {
...this.session,
updateIp: this.request.ip,
updateUa: this.request.headers['user-agent'] || '',
},
); );
} else { } else {
[this.session._id] = await token.add( [, this.session] = await token.add(
token.TYPE_SESSION, token.TYPE_SESSION,
this._handler.expireSeconds, expireSeconds,
{ {
...this.session,
createIp: this.request.ip, createIp: this.request.ip,
createUa: this.request.headers['user-agent'] || '', createUa: this.request.headers['user-agent'] || '',
updateIp: this.request.ip, updateIp: this.request.ip,
updateUa: this.request.headers['user-agent'] || '', updateUa: this.request.headers['user-agent'] || '',
...this.session,
}, },
); );
} }
const cookie = { secure: await system.get('session.secure') }; const cookie = { secure: await system.get('session.secure') };
if (this._handler.save) { if (this.session.save) {
cookie.expires = this.session.expireAt; cookie.expires = this.session.expireAt;
cookie.maxAge = this._handler.expireSeconds; cookie.maxAge = expireSeconds;
this.ctx.cookies.set('save', 'true', cookie);
} }
this.ctx.cookies.set('sid', this.session._id, cookie); this.ctx.cookies.set('sid', this.session._id, cookie);
} }
+1
View File
@@ -33,6 +33,7 @@
{% endif %} {% endif %}
<div class="row"><div class="columns"> <div class="row"><div class="columns">
<div class="text-center"> <div class="text-center">
<input type="hidden" name="csrfToken" value="{{ handler.csrfToken }}">
<input type="submit" value="{{ _('Login') }}" class="inverse expanded rounded primary button"> <input type="submit" value="{{ _('Login') }}" class="inverse expanded rounded primary button">
</div> </div>
</div></div> </div></div>
+1
View File
@@ -12,6 +12,7 @@
</div></div> </div></div>
<div class="row"><div class="columns"> <div class="row"><div class="columns">
<div class="text-center"> <div class="text-center">
<input type="hidden" name="csrfToken" value="{{ handler.csrfToken }}">
<input type="submit" value="{{ _('Send Password Reset Email') }}" class="inverse rounded primary button"> <input type="submit" value="{{ _('Send Password Reset Email') }}" class="inverse rounded primary button">
</div> </div>
</div></div> </div></div>
+1
View File
@@ -22,6 +22,7 @@
</label> </label>
</div> </div>
<div class="text-center"> <div class="text-center">
<input type="hidden" name="csrfToken" value="{{ handler.csrfToken }}">
<input type="submit" value="{{ _('Reset Password') }}" class="inverse rounded primary button"> <input type="submit" value="{{ _('Reset Password') }}" class="inverse rounded primary button">
</div> </div>
</form> </form>
+1
View File
@@ -12,6 +12,7 @@
</div></div> </div></div>
<div class="row"><div class="columns"> <div class="row"><div class="columns">
<div class="text-center"> <div class="text-center">
<input type="hidden" name="csrfToken" value="{{ handler.csrfToken }}">
<input type="submit" value="{{ _('Send Verification Email') }}" class="inverse expanded rounded primary button"> <input type="submit" value="{{ _('Send Verification Email') }}" class="inverse expanded rounded primary button">
</div> </div>
</div></div> </div></div>
+1
View File
@@ -28,6 +28,7 @@
</label> </label>
</div> </div>
<div class="text-center"> <div class="text-center">
<input type="hidden" name="csrfToken" value="{{ handler.csrfToken }}">
<input type="submit" value="{{ _('user_register') }}" class="inverse expanded rounded primary button"> <input type="submit" value="{{ _('user_register') }}" class="inverse expanded rounded primary button">
</div> </div>
</form> </form>