diff --git a/install/install.js b/install/install.js
new file mode 100644
index 000000000..c8ea6fe22
--- /dev/null
+++ b/install/install.js
@@ -0,0 +1,173 @@
+/* eslint-disable no-undef */
+///
+
+const NVM_NODEJS_ORG_MIRROR = 'https://mirrors.tuna.tsinghua.edu.cn/nodejs-release';
+const MONGODB_REPO = 'https://mirrors.tuna.tsinghua.edu.cn/mongodb/apt/ubuntu';
+const MINIO_DOWNLOAD = 'http://dl.minio.org.cn/server/minio/release/linux-amd64/minio';
+
+log.info('开始运行 HydroOJ 安装工具 / Starting HydroOJ installation tool');
+let MINIO_ACCESS_KEY = randomstring(32);
+let MINIO_SECRET_KEY = randomstring(32);
+let DATABASE_PASSWORD = randomstring(32);
+let SYSTEM_VER = 'focal';
+
+const steps = [
+ {
+ init: '正在初始化安装 / Preparing',
+ operations: [
+ 'mkdir -p /data/db /data/file ~/.hydro',
+ 'apt-get -qq update',
+ 'apt-get install -y curl wget gnupg',
+ ],
+ },
+ {
+ init: '正在安装 MongoDB / Installing MongoDB',
+ operations: [
+ () => {
+ const map = {
+ 16.04: 'xenial',
+ 18.04: 'bionic',
+ 20.04: 'focal',
+ };
+ const ver = cli.prompt('请选择系统版本:输入 16.04/18.04/20.04 中的一个并按下Enter:');
+ if (!map[ver]) log.fatal('无效输入 / Invalid input');
+ SYSTEM_VER = map[ver];
+ },
+ `echo "deb [ arch=amd64 ] ${MONGODB_REPO} ${SYSTEM_VER}/mongodb-org/4.4 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.4.list`,
+ 'wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | apt-key add -',
+ 'apt-get -qq install -y mongodb-org',
+ ],
+ },
+ {
+ init: '正在安装 NVM / Installing NVM',
+ skip: () => {
+ const nvm = fs.exist('/root/.nvm');
+ const node = !exec('node -v').code;
+ if (node && !nvm) log.fatal('检测到安装了 Node,但未使用 nvm 环境');
+ return nvm;
+ },
+ operations: [
+ () => {
+ const resp = http.request('GET', 'https://cdn.jsdelivr.net/gh/nvm-sh/nvm@v0.36.0/install.sh');
+ const script = resp.body.replace(/raw\.githubusercontent\.com\/nvm-sh\/nvm\//g, 'cdn.jsdelivr.net/gh/nvm-sh/nvm@');
+ fs.writefile('/tmp/install-nvm.sh', script);
+ },
+ 'bash /tmp/install-nvm.sh',
+ ],
+ },
+ {
+ init: '正在安装 NodeJS / Installing NodeJS',
+ operations: [
+ () => {
+ const res = exec1('bash -c "source /root/.nvm/nvm.sh && nvm install 14"', { NVM_NODEJS_ORG_MIRROR });
+ const ver = res.output.split('Now using node v')[1].split(' ')[0];
+ setenv('PATH', `/root/.nvm/versions/node/v${ver}/bin:${__env.PATH}`);
+ },
+ 'npm i yarn -g',
+ ],
+ },
+ {
+ init: '正在安装 pm2 / Installing pm2',
+ skip: () => fs.exist('/usr/local/bin/pm2'),
+ operations: ['yarn global add pm2'],
+ },
+ {
+ init: '正在创建数据库用户 / Creating database user',
+ operations: [
+ 'pm2 start mongod',
+ () => sleep(5000),
+ () => fs.writefile('/tmp/createUser.js', `\
+ db.createUser({
+ user: 'hydro',
+ pwd: '${DATABASE_PASSWORD}',
+ roles: [{ role: 'readWrite', db: 'hydro' }]
+ })`),
+ 'mongo 127.0.0.1:27017/hydro /tmp/createUser.js',
+ () => fs.writefile('/root/.hydro/config.json', JSON.stringify({
+ host: '127.0.0.1',
+ port: 27017,
+ name: 'hydro',
+ username: 'hydro',
+ password: DATABASE_PASSWORD,
+ })),
+ 'pm2 stop mongod',
+ 'pm2 del mongod',
+ ],
+ },
+ {
+ init: '正在安装 MinIO / Installing MinIO',
+ skip: () => fs.exist('/usr/bin/minio'),
+ operations: [
+ () => http.download(MINIO_DOWNLOAD, '/usr/bin/minio'),
+ 'chmod +x /usr/bin/minio',
+ () => fs.writefile('/root/.hydro/env', `MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
+ MINIO_SECRET_KEY=${MINIO_SECRET_KEY}`),
+ ],
+ },
+ {
+ init: '正在安装编译器 / Installing compiler',
+ operations: [
+ 'apt-get install -y g++ fp-compiler >/dev/null',
+ ],
+ },
+ {
+ init: '正在安装 HydroOJ / Installing HydroOJ',
+ operations: [
+ 'yarn global add hydrooj @hydrooj/ui-default @hydrooj/hydrojudge',
+ () => http.download('https://s3.undefined.moe/file/executor-amd64', '/usr/bin/sandbox'),
+ 'chmod +x /usr/bin/sandbox',
+ () => fs.writefile('/root/.hydro/addon.json', '["@hydrooj/ui-default","@hydrooj/hydrojudge"]'),
+ ],
+ },
+ {
+ init: '正在启动 / Starting',
+ operations: [
+ () => {
+ [MINIO_ACCESS_KEY, MINIO_SECRET_KEY] = fs.readfile('/root/.hydro/env').split('\n').map((i) => i.split('=')[1]);
+ },
+ `pm2 start "MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY} MINIO_SECRET_KEY=${MINIO_SECRET_KEY} minio server /data/file" --name minio`,
+ 'pm2 start "mongod --auth --bind_ip 0.0.0.0" --name mongodb',
+ () => sleep(1000),
+ 'pm2 start sandbox',
+ 'pm2 start hydrooj',
+ 'pm2 startup',
+ 'pm2 save',
+ ],
+ },
+ {
+ init: '安装完成 / Install done',
+ operations: [
+ () => {
+ [MINIO_ACCESS_KEY, MINIO_SECRET_KEY] = fs.readfile('/root/.hydro/env').split('\n').map((i) => i.split('=')[1]);
+ DATABASE_PASSWORD = loadconfig('/root/.hydro/config.json').password;
+ },
+ () => log.info('请重启终端并切换到 root 用户执行其他操作'),
+ () => log.info('Please restart terminal and switch to root user to perform other operations'),
+ () => log.info('数据库用户名:hydro / Database username: hydro'),
+ () => log.info('数据库密码:%s / Database password: %s', DATABASE_PASSWORD, DATABASE_PASSWORD),
+ () => log.info('MINIO_ACCESS_KEY=%s', MINIO_ACCESS_KEY),
+ () => log.info('MINIO_SECRET_KEY=%s', MINIO_SECRET_KEY),
+ ],
+ },
+];
+
+const { major } = fs.exist('/root/.hydro/install.cfg')
+ ? loadconfig('/root/.hydro/install.cfg', 'yaml')
+ : { major: 0 };
+
+for (let i = major; i < steps.length; i++) {
+ const step = steps[i];
+ log.info(step.init);
+ if (!(step.skip && step.skip())) {
+ for (const op of step.operations) {
+ if (typeof op === 'string') {
+ exec(op);
+ if (__code !== 0) log.fatal('Error when running %s', op);
+ } else op();
+ }
+ } else log.info('已跳过该步骤 / Step skipped');
+ fs.writefile('/root/.hydro/install.cfg', `major: ${i + 1}`);
+}
+
+exec1('rm /root/.hydro/install.cfg');
+exit(0);
diff --git a/install/install.ts b/install/install.ts
deleted file mode 100644
index d427999df..000000000
--- a/install/install.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-import './jssh';
-
-const NVM_NODEJS_ORG_MIRROR = 'https://mirrors.tuna.tsinghua.edu.cn/nodejs-release';
-const MONGODB_REPO = 'https://mirrors.tuna.tsinghua.edu.cn/mongodb/apt/ubuntu';
-const MINIO_DOWNLOAD = 'http://dl.minio.org.cn/server/minio/release/linux-amd64/minio';
-
-const map = {
- 16.04: 'xenial',
- 18.04: 'bionic',
- 20.04: 'focal',
-};
-const ver = cli.prompt('系统版本:16.04/18.04/20.04');
-if (!map[ver]) {
- log.error('无效输入 / Invalid input');
- exit(1);
-}
-log.info('开始运行 HydroOJ 安装工具 / Starting HydroOJ installation tool');
-const MINIO_ACCESS_KEY = randomstring(32);
-const MINIO_SECRET_KEY = randomstring(32);
-const DATABASE_PASSWORD = randomstring(32);
-
-function execWithNvm(str, env = {}) {
- exec(`/root/.nvm/nvm.sh && ${str}`, env);
-}
-function logAndRun(str, env = {}) {
- log.info('# %s', str);
- exec(str, env);
-}
-function logAndRunWithNvm(str, env = {}) {
- log.info('# %s', str);
- execWithNvm(str, env);
-}
-
-log.info('准备开始安装 / Preparing install');
-logAndRun('apt-get -qq update');
-logAndRun('apt-get install -y curl wget gnupg >/dev/null');
-logAndRun('wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | apt-key add -');
-logAndRun(`echo "deb [ arch=amd64 ] ${MONGODB_REPO} ${map[ver]}/mongodb-org/4.4 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.4.list`);
-logAndRun('apt-get -qq update');
-logAndRun('mkdir -p /data/db /data/file ~/.hydro');
-logAndRun('正在安装 NodeJS / Installing NodeJS');
-const resp = http.request('GET', 'https://cdn.jsdelivr.net/gh/nvm-sh/nvm@v0.36.0/install.sh');
-const script = resp.body.replace(/raw\.githubusercontent\.com\/nvm-sh\/nvm\//g, 'cdn.jsdelivr.net/gh/nvm-sh/nvm@');
-fs.writefile('/tmp/install-nvm.sh', script);
-logAndRun('bash /tmp/install-nvm.sh');
-execWithNvm('nvm install 14', { NVM_NODEJS_ORG_MIRROR });
-execWithNvm('nvm use 14');
-logAndRunWithNvm('npm i yarn -g');
-log.info('正在安装 pm2 / Installing pm2');
-logAndRunWithNvm('yarn global add pm2');
-if (!cli.bool('skipMongo')) {
- log.info('正在安装 MongoDB / Installing MongoDB');
- logAndRun('apt-get -qq install -y mongodb-org');
- logAndRunWithNvm('pm2 start mongod');
- sleep(5000);
- log.info('正在创建数据库用户 / Creating database user');
- fs.writefile('/tmp/createUser.js', `\
- db.createUser({
- user: 'hydro',
- pwd: '${DATABASE_PASSWORD}',
- roles: [{ role: 'readWrite', db: 'hydro' }]
- })`);
- logAndRun('mongo 127.0.0.1:27017/hydro /tmp/createUser.js');
- logAndRunWithNvm('pm2 stop mongod');
- logAndRunWithNvm('pm2 del mongod');
- log.info('正在启动 MongoDB / Starting MongoDB');
- logAndRunWithNvm('pm2 start "mongod --auth --bind_ip 0.0.0.0" --name mongodb');
-}
-if (!cli.bool('skipMinio')) {
- log.info('正在安装 MinIO / Installing MinIO');
- if (!fs.exist('/usr/bin/minio')) {
- http.download(MINIO_DOWNLOAD, '/usr/bin/minio');
- }
- exec('chmod +x /usr/bin/minio');
- logAndRunWithNvm(`pm2 start "MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY} MINIO_SECRET_KEY=${MINIO_SECRET_KEY} minio server /data/file" --name minio`);
-}
-log.info('正在安装编译器 / Installing compiler');
-logAndRun('apt-get install -y g++ >/dev/null');
-
-log.info('正在安装 HydroOJ / Installing HydroOJ');
-logAndRunWithNvm('yarn global add hydrooj @hydrooj/ui-default @hydrooj/hydrojudge');
-http.download('https://s3.undefined.moe/file/executor-amd64', '/usr/bin/sandbox');
-exec('chmod +x /usr/bin/sandbox');
-logAndRunWithNvm('pm2 start sandbox');
-fs.writefile('/root/.hydro/config.json', JSON.stringify({
- host: '127.0.0.1',
- port: 27017,
- name: 'hydro',
- username: 'hydro',
- password: DATABASE_PASSWORD,
-}));
-fs.writefile('/root/.hydro/addon.json', '["@hydrooj/ui-default","@hydrooj/hydrojudge"]');
-fs.writefile('/root/.hydro/env', `MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
-MINIO_SECRET_KEY=${MINIO_SECRET_KEY}`);
-logAndRunWithNvm('pm2 start hydrooj');
-logAndRunWithNvm('pm2 startup');
-logAndRunWithNvm('pm2 save');
-log.info('安装完成 / Install done');
-log.info('数据库用户名:hydro / Database username: hydro');
-log.info('数据库密码:%s / Database password: %s', DATABASE_PASSWORD, DATABASE_PASSWORD);
-log.info('MINIO_ACCESS_KEY=%s', MINIO_ACCESS_KEY);
-log.info('MINIO_SECRET_KEY=%s', MINIO_SECRET_KEY);
diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json
index b3505f8e0..b7b142866 100644
--- a/packages/hydrooj/package.json
+++ b/packages/hydrooj/package.json
@@ -1,6 +1,6 @@
{
"name": "hydrooj",
- "version": "2.24.17",
+ "version": "2.24.18",
"bin": "bin/hydrooj.js",
"main": "dist/loader.js",
"typings": "dist/loader.d.ts",
diff --git a/packages/hydrooj/src/service/server.ts b/packages/hydrooj/src/service/server.ts
index 8ccc4587b..7fa53fce9 100644
--- a/packages/hydrooj/src/service/server.ts
+++ b/packages/hydrooj/src/service/server.ts
@@ -482,6 +482,10 @@ export class Handler extends HandlerCommon {
}
async init({ domainId }) {
+ if (this.request.headers.referer) {
+ const hostname = new URL(this.request.headers.referer).hostname;
+ if (hostname !== this.request.hostname) throw new CsrfTokenError();
+ }
if (!argv.benchmark) await this.limitRate('global', 10, 88);
const [absoluteDomain, inferDomain, bdoc] = await Promise.all([
domain.get(domainId),
diff --git a/packages/ui-default/build/config/webpack.js b/packages/ui-default/build/config/webpack.js
index 0be6cf76e..8481e3592 100644
--- a/packages/ui-default/build/config/webpack.js
+++ b/packages/ui-default/build/config/webpack.js
@@ -173,10 +173,7 @@ export default function (env = {}) {
customInterpolateName: (url) => beautifyOutputUrl(url),
},
}),
- new MonacoWebpackPlugin({
- // available options are documented at https://github.com/Microsoft/monaco-editor-webpack-plugin#options
- languages: ['markdown', 'yaml', 'cpp', 'csharp', 'java', 'javascript', 'python', 'rust', 'ruby', 'php', 'pascal', 'go', 'julia'],
- }),
+ new MonacoWebpackPlugin({}),
new StaticManifestPlugin({
fileName: 'static-manifest.json',
ignore: [
diff --git a/packages/ui-default/components/scratchpad/Editor.page.styl b/packages/ui-default/components/scratchpad/Editor.page.styl
index 4728d4df4..dd7b661b1 100644
--- a/packages/ui-default/components/scratchpad/Editor.page.styl
+++ b/packages/ui-default/components/scratchpad/Editor.page.styl
@@ -1,7 +1,6 @@
.ScratchpadMonacoEditor
flex: 1
position: relative
- overflow: hidden
.cm-s-vjcm
position: absolute
diff --git a/packages/ui-default/components/scratchpad/ScratchpadEditorContainer.jsx b/packages/ui-default/components/scratchpad/ScratchpadEditorContainer.jsx
index 42533ae3e..3689440da 100644
--- a/packages/ui-default/components/scratchpad/ScratchpadEditorContainer.jsx
+++ b/packages/ui-default/components/scratchpad/ScratchpadEditorContainer.jsx
@@ -19,6 +19,22 @@ const mapDispatchToProps = (dispatch) => ({
},
});
+monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
+ noSemanticValidation: false,
+ noSyntaxValidation: false,
+});
+monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
+ target: monaco.languages.typescript.ScriptTarget.ES6,
+ allowNonTsExtensions: true,
+});
+const libSource = [
+ 'declare function readline(): string;',
+ 'declare function print(content: string): void',
+].join('\n');
+const libUri = 'ts:filename/basic.d.ts';
+monaco.languages.typescript.javascriptDefaults.addExtraLib(libSource, libUri);
+monaco.editor.createModel(libSource, 'typescript', monaco.Uri.parse(libUri));
+
export default connect(mapStateToProps, mapDispatchToProps)(class MonacoEditor extends React.PureComponent {
componentDidMount() {
const value = this.props.value || '';
diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json
index dc3874614..043a2ed9b 100644
--- a/packages/ui-default/package.json
+++ b/packages/ui-default/package.json
@@ -1,6 +1,6 @@
{
"name": "@hydrooj/ui-default",
- "version": "4.7.3",
+ "version": "4.7.4",
"author": "undefined ",
"license": "AGPL-3.0",
"main": "hydro.js",