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",