core: session sudo mode

This commit is contained in:
undefined committed 2022-10-06 16:11:02 +08:00
1 parent 52933de354
commit f075301286
11 files changed
+125 -24

No files matched your search

+3 -3
View File
@@ -17,7 +17,7 @@ import { DOMAIN_SETTINGS, DOMAIN_SETTINGS_BY_KEY } from '../model/setting';
import * as system from '../model/system';
import user from '../model/user';
import {
Handler, param, post, query, Types,
Handler, param, post, query, requireSudo, Types,
} from '../service/server';
import { log2 } from '../utils';
import { registerResolver, registerValue } from './api';
@@ -100,8 +100,8 @@ class DomainEditHandler extends ManageHandler {
this.response.redirect = this.url('domain_dashboard');
}
async postDelete({ domainId, password }) {
this.user.checkPassword(password);
@requireSudo
async postDelete({ domainId }) {
if (domainId === 'system') throw new ForbiddenError('You are not allowed to delete system domain');
if (this.domain.owner !== this.user._id) throw new ForbiddenError('You are not the owner of this domain.');
await domain.del(domainId);
+4 -1
View File
@@ -26,7 +26,7 @@ import * as training from '../model/training';
import user from '../model/user';
import * as bus from '../service/bus';
import {
ConnectionHandler, Handler, param, query, Types,
ConnectionHandler, Handler, param, query, requireSudo, Types,
} from '../service/server';
import { md5 } from '../utils';
@@ -149,6 +149,7 @@ export class HomeHandler extends Handler {
let geoip: Context['geoip'] = null;
class HomeSecurityHandler extends Handler {
@requireSudo
async get() {
// TODO(iceboy): pagination? or limit session count for uid?
const sessions = await token.getSessionListByUid(this.user._id);
@@ -169,6 +170,7 @@ class HomeSecurityHandler extends Handler {
};
}
@requireSudo
@param('current', Types.String)
@param('password', Types.String, isPassword)
@param('verifyPassword', Types.String)
@@ -180,6 +182,7 @@ class HomeSecurityHandler extends Handler {
this.response.redirect = this.url('user_login');
}
@requireSudo
@param('password', Types.String)
@param('mail', Types.Name, isEmail)
async postChangeMail(domainId: string, current: string, email: string) {
+5 -2
View File
@@ -14,8 +14,7 @@ import * as system from '../model/system';
import user from '../model/user';
import * as bus from '../service/bus';
import {
ConnectionHandler, Handler,
param, Types,
ConnectionHandler, Handler, param, requireSudo, Types,
} from '../service/server';
import { configSource, saveConfig, SystemSettings } from '../settings';
import * as judge from './judge';
@@ -142,6 +141,7 @@ class SystemScriptHandler extends SystemHandler {
}
class SystemSettingHandler extends SystemHandler {
@requireSudo
async get() {
this.response.template = 'manage_setting.html';
this.response.body.current = {};
@@ -151,6 +151,7 @@ class SystemSettingHandler extends SystemHandler {
}
}
@requireSudo
async post(args: any) {
const tasks = [];
const booleanKeys = args.booleanKeys || {};
@@ -179,6 +180,7 @@ class SystemSettingHandler extends SystemHandler {
}
class SystemConfigHandler extends SystemHandler {
@requireSudo
async get() {
this.response.template = 'manage_config.html';
let value = configSource;
@@ -191,6 +193,7 @@ class SystemConfigHandler extends SystemHandler {
};
}
@requireSudo
@param('value', Types.String)
async post(domainId: string, value: string) {
let config;
+32 -1
View File
@@ -2,7 +2,7 @@ import moment from 'moment-timezone';
import notp from 'notp';
import b32 from 'thirty-two';
import {
BlacklistedError, InvalidTokenError, LoginError,
BlacklistedError, ForbiddenError, InvalidTokenError, LoginError,
SystemError, UserAlreadyExistError, UserFacingError,
UserNotFoundError, ValidationError, VerifyPasswordError,
} from '../error';
@@ -130,6 +130,7 @@ class UserLoginHandler extends Handler {
if (!udoc.hasPriv(PRIV.PRIV_USER_PROFILE)) throw new BlacklistedError(uname);
this.session.viewLang = '';
this.session.uid = udoc._id;
this.session.sudo = null;
this.session.scope = PERM.PERM_ALL.toString();
this.session.save = rememberme;
this.response.redirect = (redirect ? decodeURIComponent(redirect) : '')
@@ -139,6 +140,34 @@ class UserLoginHandler extends Handler {
}
}
class UserSudoHandler extends Handler {
async get() {
if (!this.session.sudoArgs) throw new ForbiddenError();
this.response.template = 'user_sudo.html';
}
@param('password', Types.String)
@param('tfa', Types.String, true)
async post(domainId: string, password: string, tfa = '') {
if (!this.session.sudoArgs) throw new ForbiddenError();
await Promise.all([
this.limitRate('user_sudo', 60, 5, true),
oplog.log(this, 'user.sudo', {}),
]);
if (tfa) {
if (!this.user._tfa || !verifyToken(this.user._tfa, tfa)) throw new InvalidTokenError('2FA token invalid.');
} else {
this.user.checkPassword(password);
}
this.session.sudo = Date.now();
if (this.session.sudoArgs.method.toLowerCase() !== 'get') {
this.response.template = 'user_sudo_redirect.html';
this.response.body = this.session.sudoArgs;
this.session.sudoArgs = null;
} else this.response.redirect = this.session.sudoArgs.redirect;
}
}
class UserLogoutHandler extends Handler {
noCheckPermView = true;
@@ -148,6 +177,7 @@ class UserLogoutHandler extends Handler {
async post() {
this.session.uid = 0;
this.session.sudo = null;
this.session.scope = PERM.PERM_ALL.toString();
this.response.redirect = '/';
}
@@ -425,6 +455,7 @@ class OauthCallbackHandler extends Handler {
export async function apply(ctx) {
ctx.Route('user_login', '/login', UserLoginHandler);
ctx.Route('user_oauth', '/oauth/:type', OauthHandler);
ctx.Route('user_sudo', '/user/sudo', UserSudoHandler);
ctx.Route('user_oauth_callback', '/oauth/:type/callback', OauthCallbackHandler);
ctx.Route('user_register', '/register', UserRegisterHandler, PRIV.PRIV_REGISTER_USER);
ctx.Route('user_register_with_code', '/register/:code', UserRegisterWithCodeHandler, PRIV.PRIV_REGISTER_USER);