core&ui: goodbye, minio (#417)

This commit is contained in:
undefined authored and GitHub committed 2022-08-23 00:40:21 +08:00
1 parent 7abc0a7d1b
commit e06c86e9dd
34 files changed
+410 -322

No files matched your search

+21 -51
View File
@@ -1,7 +1,7 @@
import { exec } from 'child_process';
import { inspect } from 'util';
import Ajv from 'ajv';
import * as yaml from 'js-yaml';
import Schema from 'schemastery';
import * as check from '../check';
import { BadRequestError, ValidationError } from '../error';
import {
@@ -19,12 +19,10 @@ import {
Connection, ConnectionHandler, Handler,
param, Route, Types,
} from '../service/server';
import { schema } from '../settings';
import { configSource, saveConfig, SystemSettings } from '../settings';
import * as judge from './judge';
const logger = new Logger('manage');
const ajv = new Ajv({ useDefaults: true });
const validator = ajv.compile<any>(schema);
function set(key: string, value: any) {
if (setting.SYSTEM_SETTINGS_BY_KEY[key]) {
@@ -156,55 +154,12 @@ class SystemSettingHandler extends SystemHandler {
for (const s of this.response.body.settings) {
this.response.body.current[s.key] = system.get(s.key);
}
const hide = [];
const raw = system.get('_') || '';
let config = yaml.load(raw);
const valid = validator(config);
if (!(raw.trim() && valid)) {
const data = {};
for (const key in schema.properties) {
data[key] = {};
for (const subkey in (schema.definitions[key] as any).properties || {}) {
if (system.get(`${key}.${subkey}`)) {
data[key][subkey] = system.get(`${key}.${subkey}`);
if ((schema.definitions[key] as any).properties[subkey]?.writeOnly) {
if (data[key][subkey] instanceof Array) {
hide.push(...data[key][subkey]);
} else hide.push(data[key][subkey]);
}
}
}
}
validator(data);
config = yaml.dump(data);
} else config = yaml.dump(config);
this.response.body.hide = hide;
this.response.body.config = config;
}
async post(args: any) {
const tasks = [];
const booleanKeys = args.booleanKeys || {};
delete args.booleanKeys;
if (args._) {
if (typeof args._ !== 'string') throw new ValidationError('config');
try {
const payload = yaml.load(args._);
const valid = validator(payload);
if (!valid) {
throw new ValidationError('config', null, validator.errors[0]);
}
for (const key in payload) {
for (const subkey in payload[key]) {
tasks.push(system.set(`${key}.${subkey}`, payload[key][subkey]));
}
}
} catch (e) {
throw new ValidationError('config', null, e.message);
}
await system.set('_', args._);
delete args._;
}
for (const key in args) {
if (typeof args[key] === 'object') {
for (const subkey in args[key]) {
@@ -228,10 +183,25 @@ class SystemSettingHandler extends SystemHandler {
}
}
class SystemSettingSchemaHandler extends SystemHandler {
class SystemConfigHandler extends SystemHandler {
async get() {
this.response.body = JSON.stringify(schema);
this.response.type = 'application/json';
this.response.template = 'manage_config.html';
this.response.body = {
schema: Schema.intersect(SystemSettings).toJSON(),
value: configSource,
};
}
@param('value', Types.String)
async post(domainId: string, value: string) {
let config;
try {
config = yaml.load(value);
Schema.intersect(SystemSettings)(config);
} catch (e) {
throw new ValidationError('value');
}
await saveConfig(config);
}
}
@@ -294,7 +264,7 @@ async function apply() {
Route('manage_dashboard', '/manage/dashboard', SystemDashboardHandler);
Route('manage_script', '/manage/script', SystemScriptHandler);
Route('manage_setting', '/manage/setting', SystemSettingHandler);
Route('manage_setting_schema', '/manage/setting/schema.json', SystemSettingSchemaHandler);
Route('manage_config', '/manage/config', SystemConfigHandler);
Route('manage_user_import', '/manage/userimport', SystemUserImportHandler);
Connection('manage_check', '/manage/check-conn', SystemCheckConnHandler);
}
+22
View File
@@ -1,9 +1,11 @@
/* eslint-disable camelcase */
import { statSync } from 'fs';
import { pick } from 'lodash';
import { lookup } from 'mime-types';
import {
BadRequestError, ForbiddenError, ValidationError,
} from '../error';
import { md5 } from '../lib/crypto';
import { PRIV } from '../model/builtin';
import * as oplog from '../model/oplog';
import storage from '../model/storage';
@@ -12,6 +14,8 @@ import user from '../model/user';
import {
Handler, param, post, Route, Types,
} from '../service/server';
import { encodeRFC5987ValueChars } from '../service/storage';
import { builtinConfig } from '../settings';
import { sortFiles } from '../utils';
class SwitchLanguageHandler extends Handler {
@@ -101,6 +105,23 @@ export class FSDownloadHandler extends Handler {
}
}
export class StorageHandler extends Handler {
@param('target', Types.Name)
@param('filename', Types.Name, true)
@param('expire', Types.UnsignedInt)
@param('secret', Types.String)
async get(domainId: string, target: string, filename = '', expire: number, secret: string) {
const expected = md5(`${target}/${expire}/${builtinConfig.file.secret}`);
if (expire < Date.now()) throw new ForbiddenError('Link expired');
if (secret !== expected) throw new ForbiddenError('Invalid secret');
this.response.body = await storage.get(target);
this.response.type = (target.endsWith('.out') || target.endsWith('.ans'))
? 'text/plain'
: lookup(target) || 'application/octet-stream';
if (filename) this.response.disposition = `attachment; filename="${encodeRFC5987ValueChars(filename)}"`;
}
}
export class SwitchAccountHandler extends Handler {
@param('uid', Types.Int)
async get(domainId: string, uid: number) {
@@ -113,6 +134,7 @@ export async function apply() {
Route('switch_language', '/language/:lang', SwitchLanguageHandler);
Route('home_files', '/file', FilesHandler);
Route('fs_download', '/file/:uid/:filename', FSDownloadHandler);
Route('storage', '/storage', StorageHandler);
Route('switch_account', '/account', SwitchAccountHandler, PRIV.PRIV_EDIT_SYSTEM);
}