globalThis.__dirname=""; /******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ 417: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { function __ncc_wildcard$0 (arg) { if (arg === "alidrive") return __nccwpck_require__(593); else if (arg === "coding") return __nccwpck_require__(642); else if (arg === "googledrive") return __nccwpck_require__(844); else if (arg === "node_fs") return __nccwpck_require__(679); else if (arg === "onedrive") return __nccwpck_require__(8); else if (arg === "phony") return __nccwpck_require__(155); else if (arg === "teambition") return __nccwpck_require__(824); } function __ncc_wildcard$1 (arg) { if (arg === "simple.art") return __nccwpck_require__(533); else if (arg === "w.w.art") return __nccwpck_require__(529); else if (arg === "w.w") return __nccwpck_require__(463); } const op = __nccwpck_require__(525); const app = __nccwpck_require__(750); const { MODULES, THEMES } = __nccwpck_require__(791); const { modules, themes } = op; MODULES.forEach((k) => { modules[k] = __ncc_wildcard$0(k); }); THEMES.forEach((k) => { themes[k] = __ncc_wildcard$1(k); }); const header = __nccwpck_require__(37); const template = __nccwpck_require__(203); const admin = __nccwpck_require__(970); const invokeModule = __nccwpck_require__(228); const logger = __nccwpck_require__(885); // fake koa app app.use(header); app.use(template); app.use(admin); app.use(__nccwpck_require__(554)); app.use(__nccwpck_require__(873)); app.use(__nccwpck_require__(158)); app.use(invokeModule); module.exports = { initialize(starter) { op.initialize(starter); }, async _handle(req) { if (op.config.version === -1) { // ? 代表未加载设置,尝试加载,若加载失败自动使用默认配置 await op.readConfig(); } return app.handleRequest(req).then(({ response }) => { if (typeof response.status !== 'number' || typeof response.headers !== 'object' || typeof response.body !== 'string') { throw new Error('Internal Response Error'); } return response; }); }, async handleRequest(req) { return this._handle(req).catch((err) => { // 这一步遇到的错误一般都是请求类错误 格式错误 无法解析之类的 logger.error(err); return { status: 500, headers: { 'access-control-allow-origin': '*', 'content-type': 'application/json', }, body: JSON.stringify({ error: 'InternalError', message: err.message }), }; }); }, }; /***/ }), /***/ 791: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { // 系统配置参数,运行时只读 const config = { PORT: 8020, NODE_ENV: 'production', SIGN_DELIMITER: '.', PAGE_SIZE: 200, ID_SIGN_LEN: 7, PAGE_SIGN_LEN: 7, CACHE_TIME_FILE: 15 * 60 * 1000, CACHE_TIME_LIST: 30 * 60 * 1000, AC_PASS_FILE: '.password=', PATH_ADMIN: '/admin/', PATH_API: '/api/', PATH_DOWN: '/down:', THEMES: ['w.w.art', 'simple.art'], MODULES: ['node_fs', 'onedrive', 'coding', 'teambition', 'googledrive', 'alidrive', 'phony'], }; const configTemplate = { html: '
这是一段自定义html,你也可以在这里放置一些脚本文件
', logo: 'https://cdn.onesrc.cn/uploads/images/onepoint_30.png', name: 'DemoSite', readme: `## 部署成功 恭喜部署成功,但这并不意味着系统能使用了 接下来,你需要进入 [admin](/admin/) 页面,完成一些必须的配置 要注意,某些平台的配置参数,可能需要你在平台上自行配置 配置完成后,就可以添加云盘了 `, cors: ['*'], proxy: [], theme: config.THEMES[0], }; config.configTemplate = configTemplate; const { _P } = __nccwpck_require__(166); const commonSParams = [ _P('theme', '', '', 8, config.THEMES, false, false), _P('logo', '', '', 6, 'consume your own logo', false, false), _P('name', '', '', 6, 'consume your site name', false, false), _P('html', '', '', 6, 'embed html code', true, false), _P('readme', '', '', 6, 'markdown supported', true, false), _P('proxy', [], 'proxy for download', 4, '', false, false), _P('cors', [], 'Allow CORS', 4, '', false, false), ]; commonSParams.forEach((e) => { e.value = configTemplate[e.name]; }); config.commonSParams = commonSParams; const commonMParams = [ _P('path', '', '', 8, 'mount path', false, true), _P('module', '', '', 8, config.MODULES, false, true), _P('password', '', '', 2, 'drive password', false, false), _P('readme', '', '', 2, 'markdown supported', true, false), // _P('desc', '', '', 2, 'short desc', false, false), _P('hidden', [], '當前想要隱藏的文件或文件夾,例如 /images/today, /video/something.mp4', 2, '', false, false), ]; config.commonMParams = commonMParams; config.getAdminHtml = function (baseURL, version) { return `Just One Point
`; }; module.exports = config; /***/ }), /***/ 750: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const { RTError, cookie2Str, query2Obj } = __nccwpck_require__(166); class AppRequest { constructor({ method, path, headers, body, query, cookies, baseURL, ip }) { // UpperCase this.method = method; // parse path, path is just path,not url this.path = decodeURIComponent(/^[^?]+/.exec(path)[0]); this.headers = headers; // parse body, stream is not supposed this.body = typeof body === 'object' ? body : {}; if (method === 'POST' && typeof body === 'string' && headers['content-type']) { if (headers['content-type'].includes('application/x-www-form-urlencoded')) { this.body = query2Obj(body); } else if (headers['content-type'].includes('application/json')) { this.body = JSON.parse(body); } } // parse query, object or like ?a=1&b=2 or a=1&b=2 or /a/b?aa this.query = typeof query === 'string' ? query2Obj(query[0] === '/' ? /^[^?]+(.*)$/.exec(query)[1] : query) : query; // parse cookie this.cookies = cookies ? cookies : headers.cookie ? query2Obj(headers.cookie.replace(/;\s/g, '&')) : {}; // empty or like https://example.com or https://example.com/sub if (baseURL) { this.baseURL = baseURL; const p0 = new URL(baseURL).pathname; this.baseURLP0 = p0.endsWith('/') ? p0.slice(0, -1) : p0; } else { this.baseURL = 'https://' + headers.host; this.baseURLP0 = ''; } this.ip = ip; } } class AppResponse { constructor() { this.headers = { 'content-type': 'text/html; charset=utf-8' }; this.body = '[Default Message]'; this.update(200); } update(status, type = '', data = { message: 'success' }) { this.status = status; this.type = type; this.data = data; } get isPlain() { return this.type === ''; } get isFile() { return this.type === 'file'; } get isFolder() { return this.type === 'folder'; } get isList() { return this.type === 'list'; } get isRaw() { return this.type === 'raw'; } addCookie(name, value, options) { if (!this.headers['set-cookie']) { this.headers['set-cookie'] = []; } this.headers['set-cookie'].push(cookie2Str(name, value, options)); } } class AppContext { constructor(request) { this.request = new AppRequest(request); this.response = new AppResponse(); this.state = { level: 0, time: Date.now(), p1: '', p2: '/' }; } get path() { return this.state.p1 + this.state.p2; } throw(status, msg, properties) { throw new RTError(status, msg, properties); } assert(value, status, message, properties) { if (!value) { this.throw(status, message, properties); } } respond(status, data = 'success') { if (typeof data === 'string') { this.response.update(status, '', { message: data }); } else { this.response.update(status, '', data); } } respondList(list, nextToken = null) { this.response.update(200, 'list', { list, nextToken }); } respondOne(item, down = null) { if (item.type === 0) { this.response.update(200, 'file', { file: item }); this.response.down = down; } else { this.response.update(200, 'folder', { folder: item }); } } respondRaw(status, headers = {}, body) { headers['content-type'] = headers['content-type'] || 'text/html; charset=utf-8'; this.response.update(status, 'raw', '[raw object]'); this.response.headers = headers; this.response.body = body; } redirect(url, always = false) { if (url.startsWith('&')) { const { path, query, baseURL } = this.request; url = baseURL + encodeURI(path) + '?' + new URLSearchParams(Object.assign({}, query, query2Obj(url))).toString(); } else if (url.startsWith('?')) { const { path, baseURL } = this.request; url = baseURL + encodeURI(path) + url; } else if (!url.startsWith('//') && url.startsWith('/')) { url = this.request.baseURL + encodeURI(url); } const headers = this.response.headers; headers.Location = url; headers['content-type'] = 'text/html; charset=utf-8'; headers['referrer-policy'] = 'same-origin'; // ali-drive none referrer this.respondRaw(always ? 301 : 302, headers, `Redirecting to ${url}.`); } addCookie(name, value, options) { if (this.request.baseURLP0 && options && options.path) { options.path = this.request.baseURLP0 + options.path; } this.response.addCookie(name, value, options); } } module.exports = { middleware: [], use(fn) { if (typeof fn === 'function' && !this.middleware.includes(fn)) { this.middleware.push(fn); } return this; }, async handleRequest(req) { const ctx = new AppContext(req); const middleware = this.middleware; await (async function useMiddleware(ctx, index) { if (index < middleware.length) { return middleware[index](ctx, async () => useMiddleware(ctx, index + 1)); } })(ctx, 0); return ctx; }, }; /***/ }), /***/ 525: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const sysConfig = __nccwpck_require__(791); const logger = __nccwpck_require__(885); const { _sha1, NumberUtil, RTError, beautifyObject } = __nccwpck_require__(166); const packageInfo = __nccwpck_require__(306); module.exports = { modules: {}, themes: {}, handleRequest: null, server: { version: packageInfo.version, version2: packageInfo.version2, }, initialize(starter) { this.runtime = { time_start: Date.now(), time_read: null, time_save: null, error_read: null, error_write: null, }; this.starter = starter; this.loadConfig({ version: -1 }); }, get params() { return (this.starter.params || []).concat(sysConfig.commonSParams); }, get privateModuleParams() { return Object.entries(this.modules).reduce((o, [k, m]) => { o[k] = typeof m.params === 'function' ? m.params() : m.params || []; return o; }, {}); }, get needConfig() { return this.config.version === 1; }, loadConfig(config) { config = config || {}; config.site = Object.assign({}, sysConfig.configTemplate, config.site); config.drives = config.drives || {}; config.users = config.users || { admin: { password: 'admin' } }; config.starter = config.starter || {}; config.version = config.version || 1; const root = { $config: {}, $path: '/', next: {}, $cache: {} }; Object.entries(config.drives).forEach(([path, c]) => { const m = this.modules[c.module]; if (m) { let p = root; for (const i of path.split('/').filter((e) => e)) { if (!p.next[i]) { p.next[i] = { $config: {}, $path: p.$path + i + '/', next: {}, $cache: {} }; } p = p.next[i]; } p.$config = c; p.$module = m; } else { logger.warn('no such module: ' + path + ' ' + c.module); } }); this.root = root; this.config = config; this.salt = config.salt || ''; }, async readConfig() { logger.debug('read config...'); this.runtime.time_read = Date.now(); this.runtime.error_read = null; return this.starter .readConfig() .catch((e) => { this.runtime.error_read = e; logger.warn('read config... err:' + this.runtime.time_read); logger.warn(e); throw new RTError(500, 'ReadError', { msg: e.message }); }) .then((d) => { logger.debug('read config... ok'); this.loadConfig(d); }); }, // @Todo 后续可以考虑使用version解决 nowsh 异步保存的问题 async saveConfig(msg = '') { logger.debug('save config...'); this.runtime.time_save = Date.now(); this.runtime.last_save = msg; this.runtime.error_write = null; const copy = beautifyObject(this.config); copy.versionLast = copy.version; copy.version = Date.now(); return await this.starter .writeConfig(copy, copy.starter) .then((m) => { logger.debug('save config... ok'); this.config.version = copy.version; this.config.versionLast = copy.versionLast; this.salt = copy.salt; return m || 'success'; }) .catch((err) => { this.runtime.error_write = err; logger.error('save config... err:' + this.runtime.time_save); throw new RTError(500, 'SaveError', { msg: err.message }); }); }, sign(text, hours = 24, len = 16) { const time = NumberUtil.to62(Math.floor(Date.now() / 1000 / 3600 + hours)); return time + _sha1(this.salt + time + text).slice(0, len - 4); }, verify(text, sign, len = 16) { const time = NumberUtil.parse62(sign.slice(0, 4)) * 3600 * 1000; return time > Date.now() && sign.slice(4) === _sha1(this.salt + sign.slice(0, 4) + text).slice(0, len - 4); }, signUser(name) { const { password } = this.config.users[name]; return name + '.' + this.sign('$' + name + '.' + password + '$', 24); }, verifyUser(token) { const [n, s] = token.split('.'); const user = this.config.users[n]; return user && this.verify('$' + n + '.' + user.password + '$', s) && n; }, deepestNode(path) { let p = this.root; for (const i of path.split('/').filter((e) => e)) { if (p.next[i]) { p = p.next[i]; } else { return p; } } return p; }, // 设置p1 p2 $node, 调用模块前必须调用此函数以确认调用哪一个 parsePathBeforeInvoke(ctx, path) { const node = this.deepestNode(path); const p1 = node.$path.slice(0, -1); ctx.assert(path.startsWith(p1), 400, 'InvalidRequestPath', { path, format: p1 + '**' }); const p2 = path.slice(node.$path.length - 1); ctx.$node = node; ctx.state.p1 = p1; ctx.state.p2 = p2; }, }; /***/ }), /***/ 554: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const logger = __nccwpck_require__(885); const op = __nccwpck_require__(525); const { AC_PASS_FILE } = __nccwpck_require__(791); /** * @errors [Unauthorized,ItemNotExist] */ module.exports = async (ctx, next) => { const { hidden, password } = ctx.$node.$config; if (ctx.state.level === 0) { // hidden file if (hidden && hidden.length > 0) { ctx.assert(!hidden.find((e) => ctx.state.p2.startsWith(e)), 404, 'ItemNotExist', { path: ctx.state.p1 + ctx.state.p2 }); } // drive-pass if (password) { checkPass(ctx, 'drive_pass', password, ctx.state.p1 + '/'); } } await next(); if (ctx.state.level === 0 && ctx.response.isList) { // hidden list item if (hidden && hidden.length > 0) { const p2 = ctx.state.p2; const h = hidden.map((e) => (e.startsWith(p2) ? e.slice(p2.length) : null)).filter((e) => e && !e.includes('/')); if (h.length > 0) { ctx.response.data.list = ctx.response.data.list.filter((e) => !h.includes(e.name)); } } // list-pass const o = ctx.response.data.list.reduce( (o, e) => { if (e.name.startsWith(AC_PASS_FILE)) { o[0].push(e.name.slice(AC_PASS_FILE.length)); } else { o[1].push(e); } return o; }, [[], []] ); ctx.response.data.list = o[1]; if (o[0].length > 0) { checkPass(ctx, 'list_pass', o[0], ctx.state.p1 + ctx.state.p2); } } }; function checkPass(ctx, name, pass, path) { const { cookies, body, method, query } = ctx.request; let type = 'empty'; const uname = name.toUpperCase(); if (cookies[uname]) { type = 'expired'; if (op.verify(uname + path, cookies[uname])) { logger.log('use cookie:' + cookies[uname]); return; } } if (method === 'POST' && (body[name] || body.password)) { type = 'wrong'; // 可以使用通用字段password,也可以用对应的专用字段name const uPass = body[name] || body.password; if (uPass === pass || (Array.isArray(pass) && pass.includes(uPass))) { // 单个云盘登录 logger.log('use pass:' + uPass); ctx.addCookie(uname, op.sign(uname + path, 24 * 31), { path, maxAge: 3600 * 24 * 30 }); return; } } // 分享专用 if (method === 'GET' && query[name]) { type = 'invalid'; if (op.verify(uname + path, query[name])) { ctx.addCookie(uname, op.sign(uname + path, 24 * 31), { path, maxAge: 3600 * 24 * 30 }); return; } } ctx.throw(401, 'Unauthorized', { field: name, type }); } /***/ }), /***/ 970: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const logger = __nccwpck_require__(885); const sysConfig = __nccwpck_require__(791); const op = __nccwpck_require__(525); const SimpleRouter = __nccwpck_require__(979); const { P } = __nccwpck_require__(166); const { beautifyObject } = __nccwpck_require__(166); const { PATH_API, PATH_ADMIN, PATH_DOWN } = sysConfig; const api_router = new SimpleRouter(); api_router.setDefault((ctx) => { ctx.throw(400, 'UnsupportedAPI', { path: ctx.request.path }); }); function equalsObj(a, b) { return JSON.stringify(beautifyObject(a)) === JSON.stringify(beautifyObject(b)); } function paramsCopy(params, src) { if (!src) { return {}; } const c = {}; params.forEach(({ name }) => { if (src[name]) { c[name] = src[name]; } }); return c; } async function versionCheckAndLazySave(a, f, v, ctx) { if (!op.needConfig && equalsObj(a[0], a[1])) { logger.info('Nothing Changed, Lazy Save'); ctx.respond(200, { message: 'Nothing Changed', version: op.config.version }); } else { ctx.assert(v === op.config.version, 400, 'InvalidVersion', { version: op.config.version }); f(); ctx.respond(200, { message: await op.saveConfig(), version: op.config.version }); } } // 读写基本配置 api_router.get('config/basic', async (ctx) => { const params = op.params; if (op.needConfig) { [ P('admin_salt', String(Math.random()), '签名salt,仅限输入一次,以后不可更改', 9, '', false, false), P('admin_pass', 'admin', '密码', 9, '', false, true), P('admin_name', 'admin', '用户名,仅限输入一次,以后不可更改', 9, '', false, true), ].forEach((e) => params.unshift(e)); } ctx.respond(200, { basic: Object.assign({}, paramsCopy(sysConfig.commonSParams, op.config.site), paramsCopy(op.starter.params, op.config.starter)), params: params, version: op.config.version, }); }); api_router.post('config/basic', async (ctx) => { const { basic, version } = ctx.request.body; const c0 = paramsCopy(sysConfig.commonSParams, basic); const c1 = paramsCopy(op.starter.params, basic); const flag = op.needConfig; await versionCheckAndLazySave( [ [op.config.site, op.config.starter], [c0, c1], ], () => { if (op.config.version === 1) { op.config.salt = basic.admin_salt; const users = {}; users[basic.admin_name] = { password: basic.admin_pass }; op.config.users = users; } op.config.site = c0; op.config.starter = c1; }, version, ctx ); if (flag) { ctx.response.data.token = op.signUser(basic.admin_name); } }); // 获取所有的云盘信息,增加乐观锁,弥补token不能识别多处登录的问题 api_router.get('config/drives', async (ctx) => { ctx.respond(200, { drives: op.config.drives, moduleParams: sysConfig.commonMParams, privateModuleParams: op.privateModuleParams, version: op.config.version, }); }); // 如果要删除一个盘,需要传递一个空值,否则不执行删除操作 api_router.post('config/drives', async (ctx) => { const copy = beautifyObject(op.config.drives); const { drives, version } = ctx.request.body; Object.entries(drives).forEach(([p, c]) => { if (!c) { delete copy[p]; } else { copy[p] = paramsCopy(sysConfig.commonMParams, c); const m = op.modules[c.module]; copy[p].config = m ? paramsCopy(typeof m.params === 'function' ? m.params() : m.params, c.config) : {}; } }); await versionCheckAndLazySave( [op.config.drives, copy], () => { op.config.drives = copy; op.loadConfig(op.config); }, version, ctx ); }); api_router.post('config/export', async (ctx) => { const u = op.config.users[ctx.state.user]; ctx.assert(ctx.request.body.password === u.password, 400, 'InvalidUserAuth', { user: ctx.state.user }); ctx.respond(200, { config: op.config }); }); // 整体导入的配置 不再检验version的有效性 api_router.post('config/import', async (ctx) => { const u = op.config.users[ctx.state.user]; const { config, password } = ctx.request.body; ctx.assert(password === u.password, 400, 'InvalidUserAuth', { user: ctx.state.user }); await versionCheckAndLazySave( [op.config, config], () => { op.loadConfig(config); }, op.config.version, ctx ); }); // 修改密码 api_router.post('user/password', async (ctx) => { const u = op.config.users[ctx.state.user]; const { password0, password, version } = ctx.request.body; ctx.assert(password0 === u.password, 400, 'InvalidUserAuth', { user: ctx.state.user }); await versionCheckAndLazySave( [u.password, password], () => { // change password u.password = password; }, version, ctx ); }); api_router.get('system/runtime', async (ctx) => { ctx.respond(200, { runtime: op.runtime, version: op.config.version }); }); api_router.get('system/reload', async (ctx) => { op.config.version = -1; ctx.respond(200); }); api_router.prefix('file:', async (ctx, next, path) => { const m = ctx.request.method; const b = ctx.request.body; const $data = (ctx.$data = {}); b.path && (path = b.path); ctx.assert(path, 400, 'InvalidRequestParam', { expect: ['path'] }); if (m === 'GET') { $data.command = 'ls'; } else if (m === 'DELETE') { $data.command = 'rm'; } else if (m === 'POST') { const c = ($data.command = b.command); if (c === 'mkdir' || c === 'ren' || c === 'touch' || c === 'upload') { ctx.assert(($data.name = b.name), 400, 'InvalidRequestParam', { expect: ['name'] }); if (c === 'touch') { const { content, base64 } = b; ctx.assert(content !== undefined || base64, 400, 'InvalidRequestParam', { expect: ['content||base64'] }); $data.mime = b.mime || 'text/plain'; if (content) { $data.content = Buffer.from(content, 'utf-8'); } else if (base64) { // base64 $data.content = Buffer.from(base64, 'base64'); } } } else if (c === 'mv' || c === 'cp') { const { desPath } = b; ctx.assert(path !== desPath && op.deepestNode(path) === op.deepestNode(desPath), 400, 'InvalidRequestParam', { expect: ['desPath'] }); $data.desPath = desPath.slice(op.deepestNode(desPath).$path.length - 1); } else { ctx.throw(400, 'InvalidRequestParam', { expect: ['command'] }); } } op.parsePathBeforeInvoke(ctx, path); await next(); }); const router = new SimpleRouter(); router.prefix(PATH_ADMIN, async (ctx, _, path) => { if (path === '') { ctx.respondRaw(200, {}, sysConfig.getAdminHtml(ctx.request.baseURL, op.config.version)); } else { ctx.assert(ctx.state.level > 0, 401, 'Unauthorized', { field: 'admin-token', type: 'login please', }); } }); router.prefix(PATH_API, async (ctx, next, path) => { if (path === 'login') { const { username, password } = ctx.request.body; const u = op.config.users[username]; ctx.assert(u && password && u.password === password, 400, 'InvalidUserAuth', { username }); const token = op.signUser(username); ctx.addCookie('X_TOKEN', token, { path: '/' }); ctx.respond(200, { token, version: op.config.version }); } else if (path === 'public/site') { ctx.respond(200, { site: op.config.site, drives: Object.entries(op.config.drives).map(([path, { readme = '' }]) => ({ path, readme })), version: op.server.version, version2: op.server.version2, }); } else { ctx.assert(op.needConfig || ctx.state.level > 0, 401, 'UnauthorizedToken', { token: null }); await api_router.handle(ctx, next, path); } }); router.prefix(PATH_DOWN, async (ctx, next, path) => { ctx.$data = { command: 'download' }; op.parsePathBeforeInvoke(ctx, path); await next(); }); router.setDefault(async (ctx, next) => { ctx.state.html = ctx.request.headers.accept !== 'application/json'; ctx.state.useCache = ctx.request.query.refresh === undefined; ctx.$data = { command: 'ls' }; op.parsePathBeforeInvoke(ctx, ctx.request.path); await next(); }); module.exports = async (ctx, next) => { const { cookies, path, headers } = ctx.request; const token = headers['x-token'] || cookies.X_TOKEN; if (token) { const user = op.verifyUser(token); if (user) { ctx.state.user = user; ctx.state.level = 1; } else { ctx.addCookie('X_TOKEN', '', { path: '/' }); ctx.throw(401, 'UnauthorizedToken', { token }); } } await router.handle(ctx, next, path); }; /***/ }), /***/ 158: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const logger = __nccwpck_require__(885); const { RTError } = __nccwpck_require__(166); const { CACHE_TIME_FILE, CACHE_TIME_LIST } = __nccwpck_require__(791); module.exports = async (ctx, next) => { const path = ctx.state.p1 + ctx.state.p2; // use cache if (ctx.state.useCache) { const m = oneCache.getMsg(path, ctx.$data.page); if (m) { logger.info('cache hit'); if (m.list) { ctx.respondList(m.list, m.nextToken); } else if (m.one) { ctx.respondOne(m.one, m.down); } ctx.response.data.cached = m.time; return; } } await next(); if (ctx.response.isList) { const d = ctx.response.data; oneCache.addList(path, d.list, d.nextToken, ctx.$data.page); } else if (ctx.response.isFile) { oneCache.addOne(path, ctx.response.data.file, ctx.response.down); } else if (ctx.response.isFolder) { oneCache.addOne(path, ctx.response.data.folder); } }; class OneCache { constructor() { this.root = { next: {} }; } addList(path, list, nextToken, page = 0) { const p = this.getNode(path, true); const oNext = p.next; const next = {}; const time = Date.now(); list.forEach((e) => { next[e.name] = { value: e, next: oNext[e.name] ? oNext[e.name].next : {}, time: e.url || e.type !== 0 ? time : 0, }; }); p.next = next; if (page || nextToken) { // 一锅炖不下 if (!p.pages) { p.pages = {}; } const t = { list, nextToken, listTime: Date.now() }; t.time = t.listTime; p.pages[page] = t; } else { p.listTime = Date.now(); } } addOne(path, item, down = null) { const p = this.getNode(path, true); p.value = item; p.down = down ? JSON.stringify(down) : null; p.time = Date.now(); } getNode(path, addIfAbsent) { let p = this.root; for (const i of path.split('/').filter((e) => e)) { if (!p.next[i]) { if (!addIfAbsent) { return; } p.next[i] = { next: {} }; } p = p.next[i]; } return p; } getMsg(path, page = 0) { const p = this.getNode(path); if (!p) { return; } if (path.endsWith('/')) { if ((p.listTime || 0) > Date.now() - CACHE_TIME_LIST) { return { list: Object.values(p.next).map((e) => e.value), time: p.listTime }; } if (p.pages && p.pages[page] && p.pages[page].listTime > Date.now() - CACHE_TIME_LIST) { return p.pages[page]; } if (p.value && p.value.type === 0) { throw new RTError(400, 'ItemIsFile'); } } else { if ((p.time || 0) > Date.now() - CACHE_TIME_FILE) { return { one: p.value, down: p.down ? JSON.parse(p.down) : null, time: p.time }; } } } drop(path = '/') { if (path.endsWith('/')) { path = path.slice(0, -1); } const pPath = path.slice(0, path.lastIndexOf('/')); if (pPath === '') { this.root = { next: {} }; return; } const pp = this.getNode(pPath); if (!pp) { return; } const name = path.slice(path.lastIndexOf('/') + 1); delete pp.next[name]; delete pp.pages; } } const oneCache = new OneCache(); /***/ }), /***/ 37: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const logger = __nccwpck_require__(885); const op = __nccwpck_require__(525); module.exports = async (ctx, next) => { const { method, path, query, headers, ip } = ctx.request; logger.log(method + ' ' + path + ' ' + new URLSearchParams(query).toString() + ' ' + ip); // OPTIONS method for CORS if (method === 'OPTIONS') { // @Todo origin检查 ctx.respondRaw( 204, { 'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS', 'access-control-allow-headers': 'content-type,content-range,x-token', 'access-control-max-age': '86400', 'access-control-allow-origin': headers.origin || '*', }, '' ); return; } if (path === '/favicon.ico') { ctx.redirect(op.config.site.logo); ctx.response.status = 301; return; } await next(); // allow * temporarily if (checkCors(headers.origin, op.config.site.cors)) { ctx.response.headers['access-control-allow-origin'] = '*'; } }; function checkCors(origin, cors) { if (!origin) { return true; } if (cors) { return cors.includes('*') || cors.includes(origin); } else { return false; } } /***/ }), /***/ 228: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const logger = __nccwpck_require__(885); const op = __nccwpck_require__(525); const { ID_SIGN_LEN } = __nccwpck_require__(791); const { mime } = __nccwpck_require__(166); function signId(p2, id) { // 1-10年有效期, 纯粹是为了让生成的签名不那么一样 return id + op.sign(p2 + id, Math.floor(Math.random() * 78840) + 8760, ID_SIGN_LEN); } function verifyId(p2, id, ctx) { if (id) { // verify id const oid = id.slice(0, id.length - ID_SIGN_LEN); if (oid && op.verify((p2.endsWith('/') ? p2.slice(0, -1) : p2) + oid, id.slice(id.length - ID_SIGN_LEN), ID_SIGN_LEN)) { ctx.$data.id = oid; } else { ctx.throw(403, 'InvalidId', { id }); } } } /** * @errors [CommandNotAllowed,ItemNotExist,InvalidId] */ module.exports = async (ctx) => { const node = ctx.$node; const cmd = ctx.$data.command; const p2 = (ctx.$data.path = ctx.state.p2); if (p2 === '') { ctx.assert(cmd === 'ls', 403, 'CommandNotAllowed', { command: cmd }); const p1 = ctx.state.p1; ctx.respondOne({ type: 3, name: p1.slice(p1.lastIndexOf('/') + 1) || '$root', size: null, mime: '', time: new Date().toISOString(), }); } else if (node.$module) { verifyId(p2, ctx.request.query.id, ctx); logger.log('use: ' + node.$config.module + ', drivePath:' + ctx.state.p1); ctx.assert(node.$module[cmd], 403, 'CommandNotAllowed', { command: cmd }); await node.$module.handle(node.$config.config, ctx.$data, node.$cache, ctx); } else { ctx.assert(cmd === 'ls', 403, 'CommandNotAllowed', { command: cmd }); ctx.assert(ctx.state.p2 === '/', 404, 'ItemNotExist', { path: ctx.state.p1 + ctx.state.p2 }); ctx.respondList([]); } if (ctx.response.isList) { const list = ctx.response.data.list; list.forEach((e) => { if (e.id) { e.id = signId(p2 + e.name, e.id); } if (e.mime === undefined) { e.mime = e.type === 0 ? mime.get(e.name) : ''; } }); if (ctx.state.p2 === '/') { Object.keys(node.next).forEach((e) => list.push({ type: 3, name: e, size: null, mime: '', time: new Date().toISOString(), }) ); } // sort list.sort((e1, e2) => e2.type - e1.type || e1.name.localeCompare(e2.name)); } else if (ctx.response.isFile) { const e = ctx.response.data.file; if (e.id) { // 文档有要求,返回file时,必须为规范路径 e.id = signId(p2, e.id); } // 简化模块代码重复度 if (e.mime === undefined) { e.mime = mime.get(e.name); } } else if (ctx.response.isFolder) { const e = ctx.response.data.folder; if (e.id) { // 文档有要求,返回file时,必须为规范路径 e.id = signId(p2, e.id); } // 简化模块代码重复度 if (e.mime === undefined) { e.mime = ''; } } }; /***/ }), /***/ 873: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const logger = __nccwpck_require__(885); const op = __nccwpck_require__(525); const { PAGE_SIGN_LEN } = __nccwpck_require__(791); function signPage(p2, page) { return page + op.sign(p2 + page, Math.floor(Math.random() * 78840) + 8760, PAGE_SIGN_LEN); } function verifyPage(p2, page, ctx) { const oPage = page.slice(0, page.length - PAGE_SIGN_LEN); if (oPage && op.verify(p2 + oPage, page.slice(page.length - PAGE_SIGN_LEN), PAGE_SIGN_LEN)) { ctx.$data.page = oPage; logger.log('page: ' + oPage); } else { ctx.throw(403, 'InvalidPage', { page }); } } /** * @errors [InvalidPage] */ module.exports = async (ctx, next) => { const page = ctx.request.query.page; if (ctx.state.p2.endsWith('/') && page) { // verify page verifyPage(ctx.state.p2, page, ctx); } await next(); if (ctx.response.isList) { const data = ctx.response.data; if (data.nextToken) { data.nextToken = signPage(ctx.state.p2, data.nextToken); } } }; /***/ }), /***/ 203: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const logger = __nccwpck_require__(885); const op = __nccwpck_require__(525); const V = __nccwpck_require__(894); const { RTError } = __nccwpck_require__(166); module.exports = async (ctx, next) => { await next().catch((err) => { if (err instanceof RTError) { logger.log('request error:' + err.type); ctx.respond(err.status, { error: err.type, data: err.data, message: err.message }); } else { logger.error(err.stack); ctx.respond(400, { error: 'UnknownError', data: {}, message: err.message }); } }); if (ctx.response.isRaw) { return; } // 解决缓存引起的 多baseURL下 url不变的问题 if (ctx.response.isFile && !ctx.response.data.file.url) { ctx.response.data.file = Object.assign({}, ctx.response.data.file, { url: ctx.request.baseURL + encodeURI(ctx.state.p1 + ctx.state.p2) }); } if (ctx.state.html && ctx.request.query.json === undefined) { if (ctx.response.isFile) { if (ctx.request.query.preview === undefined) { if (ctx.response.down) { ctx.response.callback_down = ctx.response.down; } else { ctx.redirect(ctx.response.data.file.url); } return; } } const theme = op.themes[op.config.site.theme] || op.themes['w.w.art']; ctx.$V = new V(ctx); ctx.response.body = theme.render(ctx); } else { ctx.response.headers['content-type'] = 'application/json'; ctx.response.body = JSON.stringify(ctx.response.data); } }; /***/ }), /***/ 593: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const { request, IDHelper, _P } = __nccwpck_require__(166); const logger = __nccwpck_require__(885); const { RTError } = __nccwpck_require__(166); // 支持分页、id寻址 const { PAGE_SIZE } = __nccwpck_require__(791); function filter(e) { const r = { type: 1, name: e.name, time: e.updated_at, id: e.file_id, }; if (e.type === 'file') { r.type = 0; r.mime = e.mimeType; r.size = e.size; r.url = e.url; } return r; } class AliDrive extends IDHelper { static async build(config) { const m = new AliDrive(config); const { access_token, default_drive_id } = await m.refreshToken(config); // @warning refresh_token 有效期未知,暂时按永久有效处理 m.access_token = access_token; m.service.defaults.headers.Authorization = 'Bearer ' + access_token; m.drive_id = default_drive_id; return m; } constructor({ root }) { super(root || 'root'); this.service = request.create({ baseURL: 'https://api.aliyundrive.com/v2/', headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36', Origin: 'https://aliyundrive.com', Accept: '*/*', 'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', Connection: 'keep-alive', }, onResponse: (res) => { const { status, data } = res; if (status >= 300) { if (status === 404) { return Promise.reject(new RTError(404, 'ItemNotExist')); } if (!data || !data.message) { return Promise.reject(new RTError(500, 'HttpError')); } return Promise.reject(new RTError(400, 'ModuleError', data.message)); } return data; }, }); } async refreshToken({ refresh_token }) { const data = await this.service.post('https://auth.aliyundrive.com/v2/account/token', { grant_type: 'refresh_token', refresh_token, }); logger.log('ali drive access_token:' + data.access_token); return data; } async findChildItem(pid, name) { return this.service .post('file/search', { drive_id: this.drive_id, limit: 10, query: `parent_file_id = "${pid}" and name = "${name}"`, order_by: 'name ASC', }) .then((data) => data.items.map(filter).find((e) => e.name === name)); } async itemInfo(file_id) { return this.service.post('file/get', { drive_id: this.drive_id, file_id }).then(filter); } async fetchList(pid, pageToken = null) { return this.service .post('file/list', { drive_id: this.drive_id, parent_file_id: pid, limit: PAGE_SIZE, all: false, fields: '*', order_by: 'name', order_direction: 'ASC', marker: pageToken, }) .then((data) => ({ list: data.items.map(filter), next: data.next_marker, })); } } module.exports = { get params() { return [_P('refresh_token', '', '', 7, '', false, true), _P('root', '', '', 5, 'root', false, false)]; }, async handle(config, data, cache, ctx) { let $m = cache.$m || {}; ctx.assert($m.isValid || (config.refresh_token && (cache.$m = $m = await AliDrive.build(config))), 400, 'ConfigError', { fields: ['refresh_token'] }); data.id = data.id || (await $m.getIDByPath(data.path)); return this[data.command](data, cache, ctx); }, async ls({ path, id, page }, { $m }, ctx) { if (path.endsWith('/')) { const { list, next } = await $m.fetchList(id, page); ctx.assert(list.length > 0 || (await $m.itemInfo(id)).type === 1, 400, 'ItemIsFile'); ctx.respondList(list, next); } else { ctx.respondOne(await $m.itemInfo(id)); } }, }; /***/ }), /***/ 642: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const { request, RTError, IDHelper, _P } = __nccwpck_require__(166); const { PAGE_SIZE } = __nccwpck_require__(791); const ID_DELIMITER = 'l'; function filter(e) { const res = { type: 1, name: e.name, time: new Date(e.updatedAt || e.updated_at).toISOString(), size: null, }; if (!e.folderId) { res.type = 0; res.size = e.size; if (e.url.startsWith('http')) { res.url = e.url; } // 列表没有直链了 } // 记录下父id id 和类型 res.id = (e.id || e.file_id) + ID_DELIMITER + e.parentId + ID_DELIMITER + res.type; return res; } function parseId(id) { const idInfo = id.split(ID_DELIMITER); return { id: idInfo[0], pid: idInfo[1], type: Number(idInfo[2]), }; } // 因token能使用的api有限 所以改用cookie eid 默认是一年的有效期 class Coding extends IDHelper { static async build(config) { const c = new Coding(config); // 设置 X-XSRF-TOKEN await c.fetchList(0, 1); return c; } constructor({ root, api_url, cookie_eid }) { super(root); // service.defaults.headers.common['Authorization'] = 'token ' + api_token; this.service = request.create({ baseURL: api_url, headers: { Cookie: 'eid=' + cookie_eid, }, onResponse: (res) => { const { status, headers, data } = res; if (status >= 300) { return Promise.reject(new RTError(500, 'HttpError')); } if (data.code !== 0) { const code = data.code; if (code === 1302 || code === 1217) { return Promise.reject(new RTError(400, 'ItemAlreadyExist')); } if (code === 1304) { return Promise.reject(new RTError(404, 'ItemNotExist')); } return Promise.reject(new RTError(400, 'ModuleError', 'error coding code:' + data.code)); } if (headers['set-cookie']) { const match = /XSRF-TOKEN=(?[^;]+);/.exec(headers['set-cookie']); if (match && match.groups.token) { this.service.defaults.headers.Cookie = `eid=${cookie_eid};XSRF-TOKEN=${match.groups.token};`; this.service.defaults.headers['X-XSRF-TOKEN'] = match.groups.token; } } return data.data; }, }); } async findChildItem(pid, name) { const data = await this.service.get(`folders/${pid}/all/masonry?sortName=name&sortValue=asc&pageSize=10&keyword=${encodeURIComponent(name)}&recursive=false`); const e = data.list.find((e) => e.name === name); if (!e) { throw new RTError(404, 'ItemNotExist'); } return { type: e.url ? 0 : 1, name: e.name, id: e.id, pid }; } async fetchList(id, page = 1) { const data = await this.service.get(`folders/${id}/all/masonry?sortName=name&sortValue=asc&page=${page}&pageSize=${PAGE_SIZE}`); const list = data.list.map(filter); const next = data.page < data.totalPage ? data.page + 1 : null; return { list, next }; } // 1302 async mkdir(pid, name) { const params = new URLSearchParams(); params.set('parentId', pid); params.set('name', name); return filter(await this.service.post('mkdir', params)); } // 1302 async renameFolder(id, name) { const params = new URLSearchParams(); params.set('name', name); return this.service.put(`folder/${id}`, params); } // 1302 async renameFile(id, name) { const params = new URLSearchParams(); params.set('name', name); return this.service.put(`files/${id}/rename`, params); } // 1217 async touch(pid, name, content) { const params = new URLSearchParams(); params.set('name', name); params.set('content', content); return this.service.post(`files/${pid}/create`, params); } async delete(ids) { const params = new URLSearchParams(); ids.forEach((id) => params.append('fileIds', id)); return this.service.post(`/files/recycle-bin/async`, params); } // 1304 async fileInfo(id) { return filter(await this.service.get(`files/${id}/attribute`)); } // 1304 async folderInfo(id) { return filter(await this.service.get(`folders/${id}/attribute`)); } async move(pid, ids) { const params = new URLSearchParams(); params.set('toFolderId', pid); ids.forEach((id) => params.append('fileIds', id)); return this.service.post(`files/move/async`, params); } async copy(pid, ids) { const params = new URLSearchParams(); params.set('toFolderId', pid); ids.forEach((id) => params.append('fileIds', id)); return this.service.post(`files/copy/async`, params); } async asyncTask(jid) { return this.service.get(`files/async-jobs/${jid}`); } async mulDownload(ids) { const params = new URLSearchParams(); ids.forEach((id) => params.append('fileIds', id)); params.set('withDirName', 'true'); return this.service.get(`files/mixed/download/`, { params }); } } module.exports = { params() { return [ _P('api_url', '', '形如: https://<团队名>.coding.net/api/user/<用户名>/project/<项目名>/folder/', 7, '', false, true), _P('cookie_eid', '', 'cookie中的eid项', 7, '', false, true), _P('root', '', '根目录或文件夹id', 5, '0', false, false), ]; }, async handle(config, data, cache, ctx) { if ((cache.etime || 0) < Date.now()) { const fields = []; if (!/https:\/\/.+.coding.net\/api\/project\/.+\//.exec(config.api_url)) { fields.push('api_url'); } if (!config.cookie_eid) { fields.push('cookie_eid'); } if (isNaN(Number(config.root))) { delete config.root; } config.root = Number(config.root) || 0; if (fields.length > 0) { throw new RTError(400, 'ConfigError', { fields }); } cache.$U = await Coding.build(config); cache.etime = Date.now() + 3600 * 1000; } data._item = data.id ? parseId(data.id) : await cache.$U.getItemByPath(data.path); if (data.desPath) { data._desItem = data.desId ? parseId(data.desId) : await cache.$U.getItemByPath(data.desPath); } return this[data.command](data, cache, ctx); }, async ls({ path, page, _item }, { $U }, ctx) { if (path.endsWith('/')) { if (_item.type === 0) { throw new RTError(403, 'ItemIsFile'); } const { list, next } = await $U.fetchList(_item.id, page); ctx.respondList(list, next); } else { ctx.respondOne(await $U[_item.type === 0 ? 'fileInfo' : 'folderInfo'](_item.id)); } }, async mkdir({ name, _item }, { $U }) { if (_item.type === 0) { throw new RTError(403, 'ItemIsFile'); } await $U.mkdir(_item.id, name); }, async mv({ _item, _desItem }, { $U }, ctx) { if (_desItem.type === 0) { throw new RTError(403, 'ItemIsFile'); } const { job_id } = await $U.move(_desItem.id, [_item.id]); ctx.respond(202, { async: job_id }); }, async cp({ _item, _desItem }, { $U }, ctx) { if (_desItem.type === 0) { throw new RTError(403, 'ItemIsFile'); } const { job_id } = await $U.copy(_desItem.id, [_item.id]); ctx.respond(202, { async: job_id }); }, async rm({ _item }, { $U }, ctx) { const { job_id } = await $U.delete([_item.id]); ctx.respond(202, { async: job_id }); }, async ren({ name, _item }, { $U }) { await $U[_item.type === 0 ? 'renameFile' : 'renameFolder'](_item.id, name); }, async touch({ name, content, _item }, { $U }, ctx) { await $U.touch(_item.id, name, content); ctx.respond(201); }, }; /***/ }), /***/ 844: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const { request, RTError, IDHelper, _P } = __nccwpck_require__(166); const logger = __nccwpck_require__(885); // 支持分页、id寻址、中转下载 const { PAGE_SIZE } = __nccwpck_require__(791); function filter(e) { // 处理shortcut if (e.shortcutDetails) { e.id = e.shortcutDetails.targetId; e.mimeType = e.shortcutDetails.targetMimeType; } const r = { type: 1, name: e.name, time: e.modifiedTime, id: e.id, }; if (e.mimeType !== 'application/vnd.google-apps.folder') { r.type = 0; r.mime = e.mimeType; r.size = Number(e.size); } return r; } class GoogleDrive extends IDHelper { static async build(config) { const g = new GoogleDrive(config); const { access_token } = await g.refreshToken(config); g.access_token = access_token; g.service.defaults.headers.Authorization = 'Bearer ' + access_token; return g; } constructor({ root }) { super(root || 'root'); this.service = request.create({ baseURL: 'https://www.googleapis.com/', onResponse: (res) => { const { status, data } = res; if (status >= 300) { if (status === 404) { return Promise.reject(new RTError(404, 'ItemNotExist')); } if (!data || !data.error) { return Promise.reject(new RTError(500, 'HttpError')); } return Promise.reject(new RTError(400, 'ModuleError', data.error.message || data.error)); } return data; }, }); } async refreshToken({ client_id, client_secret, refresh_token }) { const o = GoogleDrive.oauth2s[0]; const data = await this.service.post( 'https://www.googleapis.com/oauth2/v4/token', new URLSearchParams({ client_id: client_id || o.client_id, client_secret: client_secret || o.client_secret, grant_type: 'refresh_token', refresh_token, }) ); logger.log('google drive access_token:' + data.access_token); return data; } async findChildItem(pid, name) { return this.service .get('drive/v3/files', { params: { includeItemsFromAllDrives: true, supportsAllDrives: true, q: `name = '${name}' and '${pid}' in parents and trashed = false`, orderBy: 'folder,name,modifiedTime desc', fields: 'files(id,name,mimeType,size,modifiedTime,shortcutDetails),nextPageToken', pageSize: 10, }, }) .then((data) => data.files.map(filter).find((e) => e.name === name)); } async itemInfo(id) { return this.service .get(`drive/v3/files/${id}`, { params: { supportsAllDrives: true, fields: 'id,name,mimeType,size,modifiedTime,shortcutDetails', }, }) .then(filter); } async fetchList(parentId, pageToken) { const params = { includeItemsFromAllDrives: true, supportsAllDrives: true, q: `'${parentId}' in parents and trashed = false`, orderBy: 'folder,name,modifiedTime desc', fields: 'files(id,name,mimeType,size,modifiedTime,shortcutDetails,webContentLink,thumbnailLink),nextPageToken', pageSize: PAGE_SIZE, }; if (pageToken) { params.pageToken = pageToken; } return this.service.get('drive/v3/files', { params }).then((data) => ({ list: data.files.map(filter), next: data.nextPageToken, })); } downInfo(id) { return { url: `https://www.googleapis.com/drive/v3/files/${id}?alt=media&supportsAllDrives=true`, headers: { Authorization: 'Bearer ' + this.access_token, }, }; } } GoogleDrive.oauth2s = [ { client_id: '202264815644.apps.googleusercontent.com', client_secret: 'X4Z3ca8xfWDb1Voo-F9a7ZxJ', redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', }, { client_id: '695250577395-08nocpbl8suogn56vjlpmifnhp5a4d7e.apps.googleusercontent.com', client_secret: 'k8xsOAGqhcmF1peWUDhZOeCK', redirect_uri: 'https://point.onesrc.cn/oauth2', }, ]; module.exports = { get params() { return [ _P('refresh_token', '', '获取refresh_token', 7, '', false, true), _P('root', '', '默认为根目录;如果想使用子目录,请填写目录id;如果想使用团队盘,请使用团队盘id', 5, 'root', false, false), _P('client_id', '', '', 5, '', false, false), _P('client_secret', '', '', 5, '', false, false), ]; }, async handle(config, data, cache, ctx) { let $m = cache.$m || {}; ctx.assert($m.isValid || (config.refresh_token && (cache.$m = $m = await GoogleDrive.build(config))), 400, 'ConfigError', { fields: ['refresh_token'] }); data.id = data.id || (await $m.getIDByPath(data.path)); return this[data.command](data, cache, ctx); }, async ls({ path, id, page }, { $m }, ctx) { if (path.endsWith('/')) { const { list, next } = await $m.fetchList(id, page); ctx.assert(list.length > 0 || (await $m.itemInfo(id)).type === 1, 400, 'ItemIsFile'); ctx.respondList(list, next); } else { const e = await $m.itemInfo(id); ctx.respondOne(e, e.type ? null : $m.downInfo(e.id)); } }, }; /***/ }), /***/ 679: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const logger = __nccwpck_require__(885); const fs = __nccwpck_require__(747); const { _P, path: _path } = __nccwpck_require__(166); const { PAGE_SIZE: PAGE } = __nccwpck_require__(791); module.exports = { params() { return [_P('root', '', '', 5, '', false, false)]; }, async handle(config, data, cache, ctx) { if (!cache.flag) { if (!config.root) { config.root = ''; } else if (config.root.endsWith('/')) { config.root = config.root.slice(0, -1); } cache.flag = true; } data.path = config.root + data.path; ctx.assert(fs.existsSync(data.path), 404, 'ItemNotExist'); return this.ls(data, cache, ctx); }, async ls({ path, page }, _1, ctx) { const stats = fs.statSync(path); if (stats.isDirectory()) { if (!path.endsWith('/')) { ctx.respondOne({ type: 1, name: _path.basename(path), size: process.platform === 'win32' ? null : stats.size, time: new Date(stats.mtime).toISOString(), }); return; } // 可 page = Number(page && page.slice(1)) || 0; const list = await Promise.all( fs.readdirSync(path).map( (fileName) => new Promise((resolve) => { fs.stat(path + fileName, (err, st) => { if (err) { logger.warn(path + ':' + fileName + ', ' + err.message); resolve(null); } else if (st.isDirectory()) { resolve({ type: 1, name: fileName, size: process.platform === 'win32' ? null : st.size, time: new Date(st.mtime).toISOString(), }); } else if (st.isFile()) { resolve({ type: 0, name: fileName, size: st.size, time: new Date(st.mtime).toISOString(), }); } else { resolve(null); } }); }) ) ); ctx.respondList(list.filter((e) => e).slice(page * PAGE, page * PAGE + PAGE), page * PAGE + PAGE < list.length ? 'l' + (page + 1) : null); } else if (stats.isFile()) { ctx.assert(!path.endsWith('/'), 403, 'ItemIsFile'); ctx.respondOne( { type: 0, name: _path.basename(path), size: stats.size, time: new Date(stats.mtime).toISOString(), }, { url: 'file://' + path } ); } else { ctx.throw(404, 'ItemNotExist'); } }, }; /***/ }), /***/ 8: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const { request, RTError } = __nccwpck_require__(166); const logger = __nccwpck_require__(885); const { _P, deleteAttributes } = __nccwpck_require__(166); const op = __nccwpck_require__(525); const { PAGE_SIZE } = __nccwpck_require__(791); function filter(e) { const res = { type: 1, name: e.name, size: e.size, mime: '', time: e.lastModifiedDateTime, }; if (e.file) { res.type = 0; res.mime = e.file.mimeType; res.url = e['@microsoft.graph.downloadUrl'] || e['@content.downloadUrl'] || null; } return res; } module.exports = { get params() { return [ _P('type', 'com', 'com:国际版 cn:世纪互联特供版', 7, ['com', 'cn'], false, true), _P('refresh_token', '', '获取refresh_token', 7, '', true, true), _P('share_url', '', 'OneDrive分享链接', 7, 'https://{?}-my.sharepoint.com/:f:/g/personal/{?}/{?}', false, true), _P('root', '', '', 5, '/', false, false), _P('api_url', '', 'sharepoint 使用此项', 5, 'https://graph.microsoft.com/v1.0/sites/{site-id}/drive/', false, false), _P('client_id', '', '', 5, '', false, false), _P('client_secret', '', '', 5, '', false, false), _P('refresh_etime', Date.now() + 3600 * 24 * 10 + '', '', 1, { hidden: true }, false, false), ]; }, async handle(config, data, cache, ctx) { // 逻辑略显臃肿 为了统一所有的onedrive if ((cache.etime || 0) < Date.now()) { if (!config.root) { config.root = ''; } else if (config.root.endsWith('/')) { config.root = config.root.slice(0, -1); } // 控制,删除无用属性 type 默认为com if (config.type !== 'cn') { deleteAttributes(config, ['type']); } if (config.share_url) { deleteAttributes(config, ['refresh_token', 'api_url', 'client_id', 'client_secret', 'refresh_etime']); if (config.type === 'cn') { cache.$point = await SharePoint.build(config.share_url); } else { cache.$one = await OneDrive.build(config); } } else if (config.refresh_token) { cache.$one = await OneDrive.build(config); deleteAttributes(config, ['share_url']); if ((config.refresh_etime || 0) < Date.now()) { config.refresh_etime = Date.now() + 30 * 24 * 3600 * 1000; config.refresh_token = cache.$one.refresh_token; await op.saveConfig('onedrive refresh_token auto save'); } } else { throw new RTError(400, 'ConfigError', { fields: ['refresh_token', 'share_url'] }); } cache.etime = Date.now() + 3600 * 1000; } if (config.root) { data.path = config.root + data.path; if (data.desPath) { data.desPath = config.root + data.desPath; } } if (cache.$point) { ctx.assert(data.command === 'ls', 403, 'CommandNotAllowed', { command: data.command }); return this.ls_cn(data, cache, ctx); } else { return this[data.command](data, cache, ctx); } }, async ls({ path, page }, { $one }, ctx) { if (!path.endsWith('/')) { // 处理文件情况 ctx.respondOne(filter(await $one.itemInfo(path))); } else { const data = await $one.fetchItems(path === '/' ? path : path.slice(0, -1), page); ctx.respondList(data.value.map(filter), data['@odata.nextLink'] ? /skiptoken=(\w*)/.exec(data['@odata.nextLink'])[1] : null); } }, // @Todo page async ls_cn({ path }, { $point }, ctx) { const data = await $point.spListData(path); const offset = (new Date().getTimezoneOffset() - data.RegionalSettingsTimeZoneBias || 0) * 3600000; if (path.endsWith('/')) { // 文件夹 ctx.respondList( data.ListData.Row.map((e) => ({ type: Number(e.FSObjType), name: e.LinkFilename, size: Number(e.SMTotalFileStreamSize), time: new Date(new Date(e.SMLastModifiedDate) - offset).toISOString(), })) ); } else { const info = await $point.spGetItemInfo(data.ListData.CurrentFolderSpItemUrl); ctx.respondOne({ type: info.file ? 0 : 1, name: info.name, size: Number(info.size), time: new Date(new Date(info.lastModifiedDateTime) - offset).toISOString(), url: info['@content.downloadUrl'], }); } }, async mkdir({ path, name }, { $one }) { await $one.mkdir(path, name); }, async mv({ path, desPath }, { $one }) { await $one.move(path, desPath); }, async cp({ path, desPath }, { $one }) { await $one.copy(path, desPath); }, async rm({ path }, { $one }, ctx) { await $one.delete(path); ctx.respond(204); }, async ren({ path, name }, { $one }) { await $one.rename(path, name); }, async touch({ path, name, content, mime }, { $one }, ctx) { await $one.touch(path, name, content, mime); ctx.respond(201); }, async upload({ path, name, size }, { $one }, ctx) { ctx.respond(201, await $one.uploadSession(path, name, size)); }, }; class OneDrive { static async build(config) { const o = new OneDrive(config); const { api_url, access_token, refresh_token } = config.share_url ? await SharePoint.getAccessToken(config.share_url) : await o.getAccessToken(config); o.api_url = api_url; o.access_token = access_token; o.refresh_token = refresh_token; o.service.defaults.baseURL = api_url; o.service.defaults.headers.Authorization = 'Bearer ' + access_token; return o; } async getAccessToken({ refresh_token, type, api_url, client_id, client_secret }) { const o = OneDrive.oauth2s[type] || OneDrive.oauth2s.com; api_url = api_url || o.api_url; return this.service .post( o.oauth_url + 'token', new URLSearchParams({ client_id: client_id || o.client_id, client_secret: client_secret || o.client_secret, grant_type: 'refresh_token', requested_token_use: 'on_behalf_of', refresh_token: refresh_token, }) ) .then((data) => (data.api_url = api_url) && data); } constructor() { this.service = request.create({ onResponse: (res) => { const { status, data } = res; if (status >= 300) { if (status === 404) { return Promise.reject(new RTError(404, 'ItemNotExist')); } if (!data || !data.error) { return Promise.reject(new RTError(500, 'HttpError')); } if (data.error_description) { return Promise.reject(new RTError(400, 'ModuleError', data.error + ':' + data.error_description)); } else { return Promise.reject(new RTError(400, 'ModuleError', data.error.code + ':' + data.error.message)); } } return data; }, }); } async itemInfo(path) { const data = await this.service.get('root' + (path === '/' ? '' : ':' + encodeURI(path))); logger.log(path + ':' + data.id); return data; } async getIdByPath(path) { return this.itemInfo(path).then(({ id }) => id); } async fetchItems(path, pageToken) { const params = { $top: PAGE_SIZE }; if (pageToken) { params.$skiptoken = pageToken; } return this.service.get('root' + (path === '/' ? '' : ':' + encodeURI(path) + ':') + '/children', { params }); } async mkdir(path, name) { return this.service.post('items/' + (await this.getIdByPath(path)) + '/children', { name: name, folder: {}, '@microsoft.graph.conflictBehavior': 'fail', }); } async move(path, desPath) { return this.service.patch('items/' + (await this.getIdByPath(path)), { parentReference: { id: await this.getIdByPath(desPath), }, }); } async copy(path, desPath) { return this.service.post('items/' + (await this.getIdByPath(path)) + '/copy', { parentReference: { id: await this.getIdByPath(desPath), }, }); } async delete(path) { return this.service.delete('items/' + (await this.getIdByPath(path))); } async rename(path, name) { return this.service.patch('items/' + (await this.getIdByPath(path)), { name }); } async touch(path, name, content, mime) { return this.service.put('items/' + (await this.getIdByPath(path)) + ':/' + name + ':/content', content, { headers: { 'Content-Type': mime, }, }); } async uploadSession(path, name) { return this.service.post('root:' + encodeURI(path + name) + ':/createUploadSession', { item: { '@microsoft.graph.conflictBehavior': 'fail', }, }); } } OneDrive.oauth2s = { com: { client_id: 'ca39c9ea-01b7-4199-b663-07cc3406196c', client_secret: 'AVMUwY_9_K8CbCXltBnNVi1~-5v6cM8qt6', oauth_url: 'https://login.microsoftonline.com/common/oauth2/v2.0/', api_url: 'https://graph.microsoft.com/v1.0/me/drive/', }, cn: { client_id: '320ca2f3-9411-401e-99df-bcf163561733', client_secret: 'VHTu]JW?m5qQxER]klkks9XHRY]y8Et0', oauth_url: 'https://login.partner.microsoftonline.cn/common/oauth2/v2.0/', api_url: 'https://microsoftgraph.chinacloudapi.cn/v1.0/me/drive/', }, }; class SharePoint { static async build(share_url) { const o = new SharePoint(); return o.init(share_url); } static async getAccessToken(share_url) { const point = await SharePoint.build(share_url); const data = await point.spListData('/'); if (data.ListSchema && data.ListSchema['.driveUrl']) { return { api_url: data.ListSchema['.driveUrl'] + '/', access_token: data.ListSchema['.driveAccessToken'].slice('access_token='.length), }; } else { throw new RTError(500, 'ConfigError', { fields: ['share_url'] }); } } async init(share_url) { const match = /https:\/\/(?[^/]*)\/:f:\/g\/personal\/(?[^/]*).*/.exec(share_url); this.cookie = await this.getCookie(match[0]); this.origin = match.groups.origin; this.account = match.groups.account; return this; } async getCookie(shareUrl) { const config = { maxRedirects: 0, validateStatus: function (status) { return status >= 200 && status < 400; }, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0', Cookie: '', }, }; const { headers } = await request.get(shareUrl, config); if (!headers['set-cookie'] || !headers['set-cookie'][0]) { throw new RTError(500, 'ModuleError', 'This sharing link has been canceled'); } logger.log('sharepoint cookie:' + headers['set-cookie'][0]); return headers['set-cookie'][0]; } async spListData(path) { const url = `https://${this.origin}/personal/${this.account}/_api/web/GetListUsingPath(DecodedUrl=@a1)/RenderListDataAsStream`; const config = { headers: { origin: 'https://' + this.origin, 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0', Cookie: this.cookie, }, params: { '@a1': `'/personal/${this.account}/Documents'`, RootFolder: `/personal/${this.account}/Documents${path}`, TryNewExperienceSingle: 'TRUE', }, }; const data = { parameters: { ViewXml: ` ${PAGE_SIZE}`, RenderOptions: 136967, AllowMultipleValueFilterForTaxonomyFields: true, AddRequiredFields: true, }, }; const res = await request.post(url, data, config); return res.data; } async spGetItemInfo(spItemUrl) { const config = { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0', Cookie: this.cookie, }, }; const res = await request.get(spItemUrl, config); return res.data; } } /***/ }), /***/ 155: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const { _P } = __nccwpck_require__(166); module.exports = { get params() { return [_P('nothing', '', '文件挂载专用,可用于补充挂载文件,请不要填写此选项', 7, '', false, false)]; }, async handle(_, data, cache, ctx) { return this[data.command](data, cache, ctx); }, async ls({ path }, _, ctx) { ctx.assert(path === '/', 404, 'ItemNotExist'); ctx.respondList([]); }, }; /***/ }), /***/ 824: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const { request, RTError, IDHelper, _P } = __nccwpck_require__(166); const { PAGE_SIZE } = __nccwpck_require__(791); function folderFilter(e) { return { type: 1, name: e.title, time: e.updated, size: null, id: e._id, }; } function fileFilter(e) { return { type: 0, name: e.fileName, time: e.updated, size: e.fileSize, id: e._id, url: e.downloadUrl, }; } class Teambition extends IDHelper { constructor({ parentId, projectId, cookie }) { super(parentId); this._projectId = projectId; this.service = request.create({ baseURL: 'https://www.teambition.com/api/', headers: { cookie }, onResponse: (res) => { const { status, data } = res; if (status >= 300) { if (status === 404) { return Promise.reject(new RTError(404, 'ItemNotExist')); } if (!data || !data.message) { return Promise.reject(new RTError(500, 'HttpError')); } return Promise.reject(new RTError(400, 'ModuleError', data.message)); } return data; }, }); } async findChildItem(pid, name) { let e = await this.fetchFolders(pid, 1, 500).then((arr) => arr.find((e) => e.name === name)); if (!e) { e = await this.fetchFiles(pid, 1, 1000).then((arr) => arr.find((e) => e.name === name)); if (!e) { throw new RTError(404, 'ItemNotExist'); } } e.pid = pid; return e; } async fetchFiles(pid, page = 1, count = PAGE_SIZE) { return this.service .get(`works`, { params: { _parentId: pid, _projectId: this._projectId, order: 'nameAsc', count: count, page: page, }, }) .then((data) => data.map(fileFilter)); } async fetchFolders(pid, page = 1, count = 200) { return this.service .get(`collections`, { params: { _parentId: pid, _projectId: this._projectId, order: 'nameAsc', count: count, page: page, }, }) .then((data) => data.map(folderFilter).filter((e) => e.name)); } async fetchList(pid, page = 1) { if (page === 1) { const folders = await this.fetchFolders(pid); const files = await this.fetchFiles(pid); const next = files.length === PAGE_SIZE ? 2 : null; return { list: folders.concat(files), next }; } else { const list = await this.fetchFiles(pid, page); // 尽可能提高准确性 const next = list.length === PAGE_SIZE ? page + 1 : null; return { list, next }; } } async fileInfo(id) { return this.service.get('works/' + id).then(fileFilter); } async folderInfo(id) { return this.service.get('collections/' + id).then(folderFilter); } } module.exports = { params() { return [_P('cookie', '', '形如TEAMBITION_SESSIONID=*; TEAMBITION_SESSIONID.sig=*', 7, '', true, true), _P('projectId', '', '项目id', 7, '', false, true), _P('parentId', '', '根目录或文件夹id', 7, '', false, true)]; }, async handle(config, data, cache, ctx) { if ((cache.etime || 0) < Date.now()) { if (!config.cookie || !config.projectId || !config.parentId) { throw new RTError(400, 'ConfigError', { fields: ['cookie', 'projectId', 'parentId'] }); } cache.$t = new Teambition(config); cache.etime = Date.now() + 3600 * 1000; } if (!data.id) { data.id = await cache.$t.getIDByPath(data.path); } return this.ls(data, cache, ctx); }, async ls({ path, id, page = 1 }, { $t }, ctx) { if (path.endsWith('/')) { await $t .fetchList(id, page) .then(({ list, next }) => { ctx.respondList(list, next); }) .catch(async (err) => { if (err.type === 'ItemNotExist') { // 不报错则是文件 报错正常退出 await $t.fileInfo(id); throw new RTError(400, 'ItemIsFile'); } }); } else { await $t .folderInfo(id) .catch((err) => { if (err.type === 'ItemNotExist') { return $t.fileInfo(id); } }) .then((e) => { const o = Object.assign({}, e); delete o.pid; ctx.respondOne(o); }); } }, }; /***/ }), /***/ 249: /***/ ((module) => { const e = { ItemNotExist({ path }) { return `文件(夹)${path || '?'}不存在`; }, Unauthorized({ field, type }) { let s = ''; if (type === 'empty') { s = '为空,请输入后重试'; } else if (type === 'invalid') { s = '已过期或不合法,请重新认证'; } else if (type === 'wrong') { s = '有误,请重新输入'; } return `字段${field}${s}`; }, CommandNotAllowed({ command }) { return `暂不支持${command}命令`; }, DriveNotExist({ path }) { return `路径${path}下未配置云盘`; }, ModuleNotExist({ module }) { return `模块${module}不存在`; }, InvalidPage({ page }) { return `分页参数${page}不合法`; }, ItemIsFile({ path }) { return `路径${path || '?'}对应一个文件,请注意path格式`; }, ConfigError({ fields }) { return `参数配置有误,请注意一下这些参数[${fields.toString()}]`; }, ModuleError(msg) { return `模块内部错误: ${msg || '???'}`; }, ReadError({ msg }) { return `配置读取失败: ${msg}`; }, SaveError({ msg }) { return `配置保存失败: ${msg}`; }, default(type) { return `发生错误${type || '?'}`; }, }; module.exports.parseErrorMsg = function (type, data) { return e[type] ? e[type](data) : e.default(type); }; /***/ }), /***/ 885: /***/ ((module) => { module.exports = console; /***/ }), /***/ 453: /***/ ((module) => { const m = { 'application/andrew-inset': ['ez'], 'application/applixware': ['aw'], 'application/atom+xml': ['atom'], 'application/atomcat+xml': ['atomcat'], 'application/atomdeleted+xml': ['atomdeleted'], 'application/atomsvc+xml': ['atomsvc'], 'application/atsc-dwd+xml': ['dwd'], 'application/atsc-held+xml': ['held'], 'application/atsc-rsat+xml': ['rsat'], 'application/bdoc': ['bdoc'], 'application/calendar+xml': ['xcs'], 'application/ccxml+xml': ['ccxml'], 'application/cdfx+xml': ['cdfx'], 'application/cdmi-capability': ['cdmia'], 'application/cdmi-container': ['cdmic'], 'application/cdmi-domain': ['cdmid'], 'application/cdmi-object': ['cdmio'], 'application/cdmi-queue': ['cdmiq'], 'application/cu-seeme': ['cu'], 'application/dash+xml': ['mpd'], 'application/davmount+xml': ['davmount'], 'application/docbook+xml': ['dbk'], 'application/dssc+der': ['dssc'], 'application/dssc+xml': ['xdssc'], 'application/ecmascript': ['ecma', 'es'], 'application/emma+xml': ['emma'], 'application/emotionml+xml': ['emotionml'], 'application/epub+zip': ['epub'], 'application/exi': ['exi'], 'application/fdt+xml': ['fdt'], 'application/font-tdpfr': ['pfr'], 'application/geo+json': ['geojson'], 'application/gml+xml': ['gml'], 'application/gpx+xml': ['gpx'], 'application/gxf': ['gxf'], 'application/gzip': ['gz'], 'application/hjson': ['hjson'], 'application/hyperstudio': ['stk'], 'application/inkml+xml': ['ink', 'inkml'], 'application/ipfix': ['ipfix'], 'application/its+xml': ['its'], 'application/java-archive': ['jar', 'war', 'ear'], 'application/java-serialized-object': ['ser'], 'application/java-vm': ['class'], 'application/javascript': ['js', 'mjs'], 'application/json': ['json', 'map'], 'application/json5': ['json5'], 'application/jsonml+json': ['jsonml'], 'application/ld+json': ['jsonld'], 'application/lgr+xml': ['lgr'], 'application/lost+xml': ['lostxml'], 'application/mac-binhex40': ['hqx'], 'application/mac-compactpro': ['cpt'], 'application/mads+xml': ['mads'], 'application/manifest+json': ['webmanifest'], 'application/marc': ['mrc'], 'application/marcxml+xml': ['mrcx'], 'application/mathematica': ['ma', 'nb', 'mb'], 'application/mathml+xml': ['mathml'], 'application/mbox': ['mbox'], 'application/mediaservercontrol+xml': ['mscml'], 'application/metalink+xml': ['metalink'], 'application/metalink4+xml': ['meta4'], 'application/mets+xml': ['mets'], 'application/mmt-aei+xml': ['maei'], 'application/mmt-usd+xml': ['musd'], 'application/mods+xml': ['mods'], 'application/mp21': ['m21', 'mp21'], 'application/mp4': ['mp4s', 'm4p'], 'application/mrb-consumer+xml': ['*xdf'], 'application/mrb-publish+xml': ['*xdf'], 'application/msword': ['doc', 'dot'], 'application/mxf': ['mxf'], 'application/n-quads': ['nq'], 'application/n-triples': ['nt'], 'application/node': ['cjs'], 'application/octet-stream': ['bin', 'dms', 'lrf', 'mar', 'so', 'dist', 'distz', 'pkg', 'bpk', 'dump', 'elc', 'deploy', 'exe', 'dll', 'deb', 'dmg', 'iso', 'img', 'msi', 'msp', 'msm', 'buffer'], 'application/oda': ['oda'], 'application/oebps-package+xml': ['opf'], 'application/ogg': ['ogx'], 'application/omdoc+xml': ['omdoc'], 'application/onenote': ['onetoc', 'onetoc2', 'onetmp', 'onepkg'], 'application/oxps': ['oxps'], 'application/p2p-overlay+xml': ['relo'], 'application/patch-ops-error+xml': ['*xer'], 'application/pdf': ['pdf'], 'application/pgp-encrypted': ['pgp'], 'application/pgp-signature': ['asc', 'sig'], 'application/pics-rules': ['prf'], 'application/pkcs10': ['p10'], 'application/pkcs7-mime': ['p7m', 'p7c'], 'application/pkcs7-signature': ['p7s'], 'application/pkcs8': ['p8'], 'application/pkix-attr-cert': ['ac'], 'application/pkix-cert': ['cer'], 'application/pkix-crl': ['crl'], 'application/pkix-pkipath': ['pkipath'], 'application/pkixcmp': ['pki'], 'application/pls+xml': ['pls'], 'application/postscript': ['ai', 'eps', 'ps'], 'application/provenance+xml': ['provx'], 'application/pskc+xml': ['pskcxml'], 'application/raml+yaml': ['raml'], 'application/rdf+xml': ['rdf', 'owl'], 'application/reginfo+xml': ['rif'], 'application/relax-ng-compact-syntax': ['rnc'], 'application/resource-lists+xml': ['rl'], 'application/resource-lists-diff+xml': ['rld'], 'application/rls-services+xml': ['rs'], 'application/route-apd+xml': ['rapd'], 'application/route-s-tsid+xml': ['sls'], 'application/route-usd+xml': ['rusd'], 'application/rpki-ghostbusters': ['gbr'], 'application/rpki-manifest': ['mft'], 'application/rpki-roa': ['roa'], 'application/rsd+xml': ['rsd'], 'application/rss+xml': ['rss'], 'application/rtf': ['rtf'], 'application/sbml+xml': ['sbml'], 'application/scvp-cv-request': ['scq'], 'application/scvp-cv-response': ['scs'], 'application/scvp-vp-request': ['spq'], 'application/scvp-vp-response': ['spp'], 'application/sdp': ['sdp'], 'application/senml+xml': ['senmlx'], 'application/sensml+xml': ['sensmlx'], 'application/set-payment-initiation': ['setpay'], 'application/set-registration-initiation': ['setreg'], 'application/shf+xml': ['shf'], 'application/sieve': ['siv', 'sieve'], 'application/smil+xml': ['smi', 'smil'], 'application/sparql-query': ['rq'], 'application/sparql-results+xml': ['srx'], 'application/srgs': ['gram'], 'application/srgs+xml': ['grxml'], 'application/sru+xml': ['sru'], 'application/ssdl+xml': ['ssdl'], 'application/ssml+xml': ['ssml'], 'application/swid+xml': ['swidtag'], 'application/tei+xml': ['tei', 'teicorpus'], 'application/thraud+xml': ['tfi'], 'application/timestamped-data': ['tsd'], 'application/toml': ['toml'], 'application/ttml+xml': ['ttml'], 'application/urc-ressheet+xml': ['rsheet'], 'application/voicexml+xml': ['vxml'], 'application/wasm': ['wasm'], 'application/widget': ['wgt'], 'application/winhlp': ['hlp'], 'application/wsdl+xml': ['wsdl'], 'application/wspolicy+xml': ['wspolicy'], 'application/xaml+xml': ['xaml'], 'application/xcap-att+xml': ['xav'], 'application/xcap-caps+xml': ['xca'], 'application/xcap-diff+xml': ['xdf'], 'application/xcap-el+xml': ['xel'], 'application/xcap-error+xml': ['xer'], 'application/xcap-ns+xml': ['xns'], 'application/xenc+xml': ['xenc'], 'application/xhtml+xml': ['xhtml', 'xht'], 'application/xliff+xml': ['xlf'], 'application/xml': ['xml', 'xsl', 'xsd', 'rng'], 'application/xml-dtd': ['dtd'], 'application/xop+xml': ['xop'], 'application/xproc+xml': ['xpl'], 'application/xslt+xml': ['xslt'], 'application/xspf+xml': ['xspf'], 'application/xv+xml': ['mxml', 'xhvml', 'xvml', 'xvm'], 'application/yang': ['yang'], 'application/yin+xml': ['yin'], 'application/zip': ['zip'], 'audio/3gpp': ['*3gpp'], 'audio/adpcm': ['adp'], 'audio/basic': ['au', 'snd'], 'audio/midi': ['mid', 'midi', 'kar', 'rmi'], 'audio/mobile-xmf': ['mxmf'], 'audio/mp3': ['*mp3'], 'audio/mp4': ['m4a', 'mp4a'], 'audio/mpeg': ['mpga', 'mp2', 'mp2a', 'mp3', 'm2a', 'm3a'], 'audio/ogg': ['oga', 'ogg', 'spx'], 'audio/s3m': ['s3m'], 'audio/silk': ['sil'], 'audio/wav': ['wav'], 'audio/wave': ['*wav'], 'audio/webm': ['weba'], 'audio/xm': ['xm'], 'font/collection': ['ttc'], 'font/otf': ['otf'], 'font/ttf': ['ttf'], 'font/woff': ['woff'], 'font/woff2': ['woff2'], 'image/aces': ['exr'], 'image/apng': ['apng'], 'image/bmp': ['bmp'], 'image/cgm': ['cgm'], 'image/dicom-rle': ['drle'], 'image/emf': ['emf'], 'image/fits': ['fits'], 'image/g3fax': ['g3'], 'image/gif': ['gif'], 'image/heic': ['heic'], 'image/heic-sequence': ['heics'], 'image/heif': ['heif'], 'image/heif-sequence': ['heifs'], 'image/hej2k': ['hej2'], 'image/hsj2': ['hsj2'], 'image/ief': ['ief'], 'image/jls': ['jls'], 'image/jp2': ['jp2', 'jpg2'], 'image/jpeg': ['jpeg', 'jpg', 'jpe'], 'image/jph': ['jph'], 'image/jphc': ['jhc'], 'image/jpm': ['jpm'], 'image/jpx': ['jpx', 'jpf'], 'image/jxr': ['jxr'], 'image/jxra': ['jxra'], 'image/jxrs': ['jxrs'], 'image/jxs': ['jxs'], 'image/jxsc': ['jxsc'], 'image/jxsi': ['jxsi'], 'image/jxss': ['jxss'], 'image/ktx': ['ktx'], 'image/png': ['png'], 'image/sgi': ['sgi'], 'image/svg+xml': ['svg', 'svgz'], 'image/t38': ['t38'], 'image/tiff': ['tif', 'tiff'], 'image/tiff-fx': ['tfx'], 'image/webp': ['webp'], 'image/wmf': ['wmf'], 'message/disposition-notification': ['disposition-notification'], 'message/global': ['u8msg'], 'message/global-delivery-status': ['u8dsn'], 'message/global-disposition-notification': ['u8mdn'], 'message/global-headers': ['u8hdr'], 'message/rfc822': ['eml', 'mime'], 'model/3mf': ['3mf'], 'model/gltf+json': ['gltf'], 'model/gltf-binary': ['glb'], 'model/iges': ['igs', 'iges'], 'model/mesh': ['msh', 'mesh', 'silo'], 'model/mtl': ['mtl'], 'model/obj': ['obj'], 'model/stl': ['stl'], 'model/vrml': ['wrl', 'vrml'], 'model/x3d+binary': ['*x3db', 'x3dbz'], 'model/x3d+fastinfoset': ['x3db'], 'model/x3d+vrml': ['*x3dv', 'x3dvz'], 'model/x3d+xml': ['x3d', 'x3dz'], 'model/x3d-vrml': ['x3dv'], 'text/cache-manifest': ['appcache', 'manifest'], 'text/calendar': ['ics', 'ifb'], 'text/coffeescript': ['coffee', 'litcoffee'], 'text/css': ['css'], 'text/csv': ['csv'], 'text/html': ['html', 'htm', 'shtml'], 'text/jade': ['jade'], 'text/jsx': ['jsx'], 'text/less': ['less'], 'text/markdown': ['markdown', 'md'], 'text/mathml': ['mml'], 'text/mdx': ['mdx'], 'text/n3': ['n3'], 'text/plain': ['txt', 'text', 'conf', 'def', 'list', 'log', 'in', 'ini'], 'text/richtext': ['rtx'], 'text/rtf': ['*rtf'], 'text/sgml': ['sgml', 'sgm'], 'text/shex': ['shex'], 'text/slim': ['slim', 'slm'], 'text/stylus': ['stylus', 'styl'], 'text/tab-separated-values': ['tsv'], 'text/troff': ['t', 'tr', 'roff', 'man', 'me', 'ms'], 'text/turtle': ['ttl'], 'text/uri-list': ['uri', 'uris', 'urls'], 'text/vcard': ['vcard'], 'text/vtt': ['vtt'], 'text/xml': ['*xml'], 'text/yaml': ['yaml', 'yml'], 'video/3gpp': ['3gp', '3gpp'], 'video/3gpp2': ['3g2'], 'video/h261': ['h261'], 'video/h263': ['h263'], 'video/h264': ['h264'], 'video/jpeg': ['jpgv'], 'video/jpm': ['*jpm', 'jpgm'], 'video/mj2': ['mj2', 'mjp2'], 'video/mp2t': ['ts'], 'video/mp4': ['mp4', 'mp4v', 'mpg4'], 'video/mpeg': ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v'], 'video/ogg': ['ogv'], 'video/quicktime': ['qt', 'mov'], 'video/webm': ['webm'], }; const map = {}; Object.keys(m).forEach((t) => { m[t].forEach((e) => { map[e] = t; }); }); map.mkv = 'video/x-matroska'; map.flv = 'video/x-flv'; map.m3u8 = 'application/x-mpegURL'; module.exports = map; /***/ }), /***/ 166: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { exports.query2Obj = function (s = '', o = {}) { for (const [k, v] of new URLSearchParams(s)) { o[k] = v; } return o; }; exports.cookie2Str = function (n, v, o = {}) { let s = encodeURIComponent(n) + '=' + encodeURIComponent(v); const { maxAge, domain, path, expires, httpOnly, secure, sameSite } = o; s += typeof maxAge === 'number' ? '; Max-Age=' + maxAge : ''; domain ? (s += '; Domain=' + domain) : ''; path ? (s += '; Path=' + path) : ''; expires ? (s += '; Expires=' + expires) : ''; httpOnly ? (s += '; HttpOnly') : ''; secure ? (s += '; Secure') : ''; sameSite ? (s += '; SameSite=' + sameSite) : ''; return s; }; exports._sha1 = __nccwpck_require__(494); exports.path = { basename: (s) => (s ? s.slice(s.lastIndexOf('/') + 1) : ''), extname: (s) => (s ? s.slice(s.lastIndexOf('.') + 1) : ''), }; const request = (exports.request = __nccwpck_require__(896)); request.defaults.timeout = 5000; exports.exposeHeadersWhenProxy = function (k) { if (typeof k !== 'string') { return false; } k = k.toLowerCase(); if (k.startsWith('content-')) { return k; } return ['accept-ranges', 'date'].includes(k); }; const mime = __nccwpck_require__(453); exports.mime = { get: (path) => mime[path.slice(path.lastIndexOf('.') + 1)] || 'application/vnd.op-unknown', }; const NUM_CHARS = {}; '0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'.split('').forEach((v, i) => { NUM_CHARS[i] = v; NUM_CHARS[v] = i; }); exports.NumberUtil = { parse62: (s) => { let num = 0, base = 1; s.split('') .reverse() .forEach((c) => { num += NUM_CHARS[c] * base; base *= 62; }); return num; }, to62: (n) => { const arr = []; while (n > 0) { arr.push(NUM_CHARS[n % 62]); n = Math.floor(n / 62); } if (arr.length === 0) { return '0'; } return arr.reverse().join(''); }, }; const { parseErrorMsg } = __nccwpck_require__(249); class RTError extends Error { constructor(status, type, data) { super(parseErrorMsg(type, data || {})); this.status = status; this.type = type; this.data = data || {}; this.expose = true; } } exports.RTError = RTError; const logger = __nccwpck_require__(885); class IDHelper { constructor(root) { this.root = root; this.icache = {}; this.etime = Date.now() + 3600 * 1000; } get isValid() { return Date.now() < this.etime; } async findChildItem(pid, name) { return Promise.reject(new RTError(500, 'unsupported method: findChildItem(' + pid + ',' + name + ')')); } async getIDByPath(path = '/') { return this.getItemByPath(path).then((e) => e.id); } async getItemByPath(path) { return this._getItemByPath( path.split('/').filter((e) => e), { type: 1, id: this.root } ); } async _getItemByPath(paths, item) { if (paths.length === 0) { return item; } const pid = item.id; const cache = this.icache[pid] || {}; const name = paths.shift(); if (!cache[name] || cache[name].etime < Date.now()) { logger.info('pid:' + pid + ' ' + name); const cItem = await this.findChildItem(pid, name); if (!cItem) { throw new RTError(404, 'ItemNotExist'); } cItem.etime = Date.now() + 300000; cache[name] = cItem; // 保证path中出现的都是文件夹 if (cItem.type !== 1 && paths.length > 0) { throw new RTError(404, 'ItemNotExist'); } } this.icache[pid] = cache; return this._getItemByPath(paths, cache[name]); } } exports.IDHelper = IDHelper; exports.P = exports._P = (name, value, desc, level, meta, textarea, star) => { const r = { name, value, desc, level }; if (Array.isArray(meta)) { r.select = meta; } else { r.placeholder = meta; if (textarea) { r.textarea = true; } } if (star) { r.star = true; } if (meta.hidden) { r.hidden = true; } return r; }; exports.beautifyObject = function beautifyObject(ob) { if (Array.isArray(ob)) { return ob.map((e) => beautifyObject(e)); } if (typeof ob === 'string' || typeof ob === 'number' || typeof ob === 'boolean') { return ob; } const nob = {}; Object.keys(ob) .sort() .forEach((k) => { nob[k] = typeof ob[k] === 'object' ? beautifyObject(ob[k]) : ob[k]; }); return nob; }; exports.deleteAttributes = function (obj, arr) { arr.forEach((e) => delete obj[e]); }; /***/ }), /***/ 979: /***/ ((module) => { const SimpleRouter = function () { this.routers = { GET: {}, POST: {}, DELETE: {}, prefix: [], regex: [], default: () => {}, }; }; SimpleRouter.prototype.add = function (m, p, f) { if (Array.isArray(m)) { m.forEach((e) => { this.routers[e][p] = f; }); } if (typeof m === 'string') { this.routers[m][p] = f; } }; SimpleRouter.prototype.get = function (p, f) { this.routers.GET[p] = f; }; SimpleRouter.prototype.post = function (p, f) { this.routers.POST[p] = f; }; SimpleRouter.prototype.delete = function (p, f) { this.routers.DELETE[p] = f; }; SimpleRouter.prototype.setDefault = function (f) { this.routers.default = f; }; SimpleRouter.prototype.regex = function (p, f) { this.routers.regex.push({ p, f }); }; SimpleRouter.prototype.prefix = function (p, f) { this.routers.prefix.push({ p, f }); }; SimpleRouter.prototype.handle = async function (ctx, next, path) { const m = ctx.request.method; if (this.routers[m] && this.routers[m][path]) { return this.routers[m][path](ctx); } const item = this.routers.regex.find(({ p }) => p.test(path)); if (item) { return item.f(ctx, next, path); } const item1 = this.routers.prefix.find(({ p }) => path.startsWith(p)); if (item1) { return item1.f(ctx, next, path.slice(item1.p.length)); } return this.routers.default(ctx, next, path); }; module.exports = SimpleRouter; /***/ }), /***/ 191: /***/ ((module) => { function request({ method, url, headers, body }, config) { return new Promise((resolve, reject) => { const abort = { state: false, schedule: null }; if (config.timeout) { abort.schedule = setTimeout(() => { abort.state = true; reject(new Error('timeout of ' + config.timeout + 'ms exceeded')); }, config.timeout); } fetch(url, { method, headers: new Headers(headers), body, redirect: 'manual', }) .then((res) => { if (abort.state) { return; } if (abort.schedule) { clearTimeout(abort.schedule); } const h = {}; for (const [k, v] of res.headers) { h[k] = v; } if (h['set-cookie']) { // set-cookie is special h['set-cookie'] = h['set-cookie'].split(/(? e.trim()); } const response = { status: res.status, headers: h, data: '', }; if (config.responseType === 'stream') { response.data = res.body; return resolve(response); } if ((response.status >= 300 && response.status < 400) || response.status === 204 || method === 'HEAD') { return resolve(response); } // just delete if (['gzip', 'compress', 'deflate'].includes(response.headers['content-encoding'])) { delete response.headers['content-encoding']; } let responseData = res; switch (config.responseType) { case 'arraybuffer': responseData = responseData.arrayBuffer(); break; case 'blob': responseData = responseData.blob(); break; default: responseData = responseData.text(); } // consume response if (!responseData) { reject(new Error('Failed to resolve response stream.')); } else { responseData.then( (data) => { response.data = data; resolve(response); }, (dataErr) => { reject(dataErr || new Error('Stream decode error')); } ); } }) .catch((err) => { if (abort.state) { return; } if (abort.schedule) { clearTimeout(abort.schedule); } if (err instanceof Error) { reject(err); } else { reject(new Error('Network Error')); } }); }); } module.exports = request; /***/ }), /***/ 896: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { /** * 很純粹的http请求工具 * * 不支持重定向,需要手动处理 * * method 需要大写 * url 可以包含中文字符 * headers 字段大写格式 * responseType 支持 json text * * 支持默认baseURL, headers */ function setIfUndefined(o, a, v) { o[a] === undefined ? (o[a] = v) : ''; } const adapters = {}; adapters.n = __nccwpck_require__(541); adapters.f = __nccwpck_require__(191); function getDefaultAdapter() { return adapters[typeof fetch === 'function' ? 'f' : 'n']; } function mergeConfig(config1, config2) { return Object.assign({}, config1, config2, { headers: Object.assign({}, config1.headers, config2.headers) }); } function buildFullURL(url, baseURL, params) { const u = new URL(url, baseURL || 'http://example.com'); if (!['http:', 'https:'].includes(u.protocol)) { // url中包含了 : if (url[0] === '/') { u.href = baseURL; u.pathname = url; } else { u.href = baseURL + url; } } if (params) { const _searchParams = u.searchParams; Object.entries(params).forEach(([k, v]) => _searchParams.set(k, v.toString())); } return u.href; } const defaults = { baseURL: '', headers: {}, responseType: 'json', adapter: getDefaultAdapter(), onResponse: (d) => d, }; class Request { constructor(config) { this.defaults = config; } async request(config) { config = mergeConfig(this.defaults, config); const { url, method, headers, body, data, baseURL, params } = config; const req = { method: (method || 'GET').toUpperCase(), headers }; req.url = buildFullURL(url, baseURL, params); setIfUndefined(headers, 'User-Agent', 'tiny-request/0.0'); setIfUndefined(headers, 'Accept', 'application/json, text/plain, */*'); if (['GET', 'HEAD'].includes(req.method)) { req.body = null; } else if (body) { req.body = body; } else if (data instanceof URLSearchParams) { setIfUndefined(headers, 'Content-Type', 'application/x-www-form-urlencoded;charset=utf-8'); req.body = data.toString(); } else if (data && typeof data === 'object') { setIfUndefined(headers, 'Content-Type', 'application/json;charset=utf-8'); req.body = JSON.stringify(data); } else if (typeof data === 'string') { req.body = data; } else { req.body = ''; } return config .adapter(req, config) .then((res) => { if (res.data && config.responseType === 'json' && typeof res.data === 'string') { try { res.data = JSON.parse(res.data); } catch (e) {} } res.request = req; res.config = config; return res; }) .then(config.onResponse) .catch((e) => { e.isHttpError = true; if (Object.getPrototypeOf(e) === Error.prototype) { e.message = 'Internal HttpError: ' + e.message; } return Promise.reject(e); }); } async reject() {} } // Provide aliases for supported request methods ['delete', 'get', 'head', 'options'].forEach((m) => { Request.prototype[m] = function (url, config = {}) { config.method = m; config.url = url; return this.request(config); }; }); ['post', 'put', 'patch'].forEach((m) => { Request.prototype[m] = function (url, data = '', config = {}) { config.method = m; config.url = url; config.data = data; return this.request(config); }; }); // Create the default instance to be exported const request = new Request(defaults); request.Request = Request; // Factory for creating new instances request.create = function create(config) { return new Request(mergeConfig(this.defaults, config)); }; module.exports = request; // Allow use of default import syntax in TypeScript module.exports.default = request; /***/ }), /***/ 541: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const http = __nccwpck_require__(605); const https = __nccwpck_require__(211); const zlib = __nccwpck_require__(761); // utf8解码未处理bom async function request({ method, url, headers, body }, config) { const u = new URL(url); const options = { hostname: u.hostname, port: u.port, path: u.pathname + u.search, method, headers, }; if (config.proxy) { options.hostname = config.proxy.host; options.port = config.proxy.port; options.path = url; headers.Host = u.host; } return new Promise((resolve, reject) => { const transport = u.protocol === 'https:' && !config.proxy ? https : http; // Create the request const req = transport.request(options, function handleResponse(res) { if (req.aborted) { return; } const response = { status: res.statusCode, headers: res.headers, data: '', }; // forward stream, do nothing! if (config.responseType === 'stream') { response.data = res; resolve(response); return; } // if redirect or no content or HEAD method, do not need body! if ((response.status >= 300 && response.status < 400) || response.status === 204 || method === 'HEAD') { resolve(response); return; } let stream = res; if (['gzip', 'compress', 'deflate'].includes(response.headers['content-encoding'])) { // add the unzipper to the body stream processing pipeline stream = stream.pipe(zlib.createUnzip()); // remove the content-encoding in order to not confuse downstream operations delete response.headers['content-encoding']; } const responseBuffer = []; stream.on('data', function handleStreamData(chunk) { responseBuffer.push(chunk); }); stream.on('error', function handleStreamError(err) { if (req.aborted) { return; } reject(err); }); stream.on('end', function handleStreamEnd() { let responseData = Buffer.concat(responseBuffer); if (config.responseType !== 'arraybuffer') { responseData = responseData.toString('utf8'); } response.data = responseData; resolve(response); }); }); // Handle errors req.on('error', function handleRequestError(err) { if (req.aborted) { return; } reject(err); }); // Handle request timeout if (config.timeout) { // Sometime, the response will be very slow, and does not respond, the connect event will be block by event loop system. // And timer callback will be fired, and abort() will be invoked before connection, then get "socket hang up" and code ECONNRESET. // At this time, if we have a large number of request, nodejs will hang up some socket on background. and the number will up and up. // And then these socket which be hang up will devoring CPU little by little. // ClientRequest.setTimeout will be fired on the specify milliseconds, and can make sure that abort() will be fired after connect. req.setTimeout(config.timeout, function handleRequestTimeout() { req.abort(); reject(new Error('timeout of ' + config.timeout + 'ms exceeded')); }); } // Send the request req.end(body); }); } module.exports = request; /***/ }), /***/ 494: /***/ ((module) => { // https://github.com/jbt/tiny-hashes/blob/master/sha1/sha1.js function sha1(b) { var i, W = [], A, B, C, D, h = [(A = 0x67452301), (B = 0xefcdab89), ~A, ~B, 0xc3d2e1f0], words = [], s = unescape(encodeURI(b)) + '\x80', j = s.length; // See "Length bits" in notes words[(b = (--j / 4 + 2) | 15)] = j * 8; for (; ~j; ) { // j !== -1 words[j >> 2] |= s.charCodeAt(j) << (8 * ~j--); // words[j >> 2] |= s.charCodeAt(j) << 24 - 8 * j--; } for (i = j = 0; i < b; i += 16) { A = h; for ( ; j < 80; A = [ A[4] + (W[j] = j < 16 ? ~~words[i + j] : (s * 2) | (s < 0)) + // s << 1 | s >>> 31 1518500249 + [(B & C) | (~B & D), (s = (B ^ C ^ D) + 341275144), ((B & C) | (B & D) | (C & D)) + 882459459, s + 1535694389][/* 0 | (j++ / 20)*/ (j++ / 5) >> 2] + (((s = A[0]) << 5) | (s >>> 27)), s, (B << 30) | (B >>> 2), C, D, ] ) { s = W[j - 3] ^ W[j - 8] ^ W[j - 14] ^ W[j - 16]; B = A[1]; C = A[2]; D = A[3]; } // See "Integer safety" in notes for (j = 5; j; ) { h[--j] += A[j]; } // j === 0 } for (s = ''; j < 40; ) { // s += ((h[j >> 3] >> 4 * ~j++) & 15).toString(16); s += ((h[j >> 3] >> ((7 - j++) * 4)) & 15).toString(16); // s += ((h[j >> 3] >> -4 * ++j) & 15).toString(16); } return s; } module.exports = sha1; /***/ }), /***/ 894: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const op = __nccwpck_require__(525); class V { constructor(ctx) { this.ctx = ctx; this.request = ctx.request; this.response = ctx.response; this.site = op.config.site; } get navs() { const path = this.request.path; const q = this.request.query; const arr = [{ name: 'root' }]; path.split('/') .filter((e) => e) .forEach((e) => { arr.push({ name: e }); }); if (path.endsWith('/')) { let p = './'; for (let i = arr.length - 1; i >= 0; i--) { arr[i].href = p; p += '../'; } if (q.id) { arr[arr.length - 1].href += '?id=' + encodeURIComponent(q.id); } } else { arr[arr.length - 1].href = (q.preview !== undefined ? '?preview' : '?') + this.appendReqQueryID; let p = './'; for (let i = arr.length - 2; i >= 0; i--) { arr[i].href = p; p += '../'; } } return arr; } get list() { return this.response.data.list; } get hasPrev() { return this.response.data.prevToken; } get prevHref() { return '?page=' + encodeURIComponent(this.response.data.prevToken) + this.appendReqQueryID; } get hasParent() { return this.request.path !== '/'; } get hasNext() { return this.response.data.nextToken; } get nextHref() { return '?page=' + encodeURIComponent(this.response.data.nextToken) + this.appendReqQueryID; } get appendReqQueryID() { const id = this.request.query.id; return id ? '&id=' + encodeURIComponent(id) : ''; } get isEmpty() { return this.response.data.list.length === 0; } previewHref(e, p = true) { if (e.type === 0) { return `${e.name}${e.id ? '?id=' + encodeURIComponent(e.id) : ''}${p ? (e.id ? '&preview' : '?preview') : ''}`; } else { return `${e.name}/${e.id ? '?id=' + encodeURIComponent(e.id) : ''}`; } } get file() { return this.response.data.file; } get previewType() { const f = this.file; const m = f.mime; if (m.startsWith('image/')) { return 'image'; } if (m.startsWith('video/')) { return 'video'; } if (m.startsWith('audio/')) { return 'audio'; } if (['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'mpp', 'rtf', 'vsd', 'vsdx'].includes(f.name.slice(f.name.lastIndexOf('.') + 1))) { return 'office'; } if (m.endsWith('pdf')) { return 'pdf'; } if (f.size < 16 * 1024) { return 'text'; } if (m.startsWith('text')) { return 'bigText'; } return ''; } // @warning 考虑放弃proxy功能 get downloadUrl() { return (this.request.cookies.PROXY_DOWN || '') + this.response.data.file.url; } get hasPassword() { return this.response.data.error === 'Unauthorized'; } get passwordHint() { const { type, field } = this.response.data.data; return field + ' ' + type; } get jsonData() { return JSON.stringify(this.response.data, null, 2); } get readme() { return ((this.ctx.$node || {}).$config || {}).readme || op.config.site.readme; } get readmeUrl() { return this.response.isList && this.response.data.list.find((e) => e.name === 'README.md') ? 'README.md' : ''; } get cacheTime() { return this.response.data.cached; } get refreshHref() { const q = this.request.query; return '?refresh' + (q.preview === undefined ? '' : '&preview') + this.appendReqQueryID + (q.page ? '&page=' + encodeURIComponent(q.page) : ''); } encodeURIComponent(u) { return encodeURIComponent(u); } } module.exports = V; /***/ }), /***/ 467: /***/ ((module) => { "use strict"; /*! art-template@runtime | https://github.com/aui/art-template */ var globalThis = typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : {}; var runtime = Object.create(globalThis); var ESCAPE_REG = /["&'<>]/; /** * 编码模板输出的内容 * @param {any} content * @return {string} */ runtime.$escape = function (content) { return xmlEscape(toString(content)); }; /** * 迭代器,支持数组与对象 * @param {array|Object} data * @param {function} callback */ runtime.$each = function (data, callback) { if (Array.isArray(data)) { for (var i = 0, len = data.length; i < len; i++) { callback(data[i], i); } } else { for (var _i in data) { callback(data[_i], _i); } } }; // 将目标转成字符 function toString(value) { if (typeof value !== 'string') { if (value === undefined || value === null) { value = ''; } else if (typeof value === 'function') { value = toString(value.call(value)); } else { value = JSON.stringify(value); } } return value; } // 编码 HTML 内容 function xmlEscape(content) { var html = '' + content; var regexResult = ESCAPE_REG.exec(html); if (!regexResult) { return content; } var result = ''; var i = void 0, lastIndex = void 0, char = void 0; for (i = regexResult.index, lastIndex = 0; i < html.length; i++) { switch (html.charCodeAt(i)) { case 34: char = '"'; break; case 38: char = '&'; break; case 39: char = '''; break; case 60: char = '<'; break; case 62: char = '>'; break; default: continue; } if (lastIndex !== i) { result += html.substring(lastIndex, i); } lastIndex = i + 1; result += char; } if (lastIndex !== i) { return result + html.substring(lastIndex, i); } else { return result; } } module.exports = runtime; /***/ }), /***/ 533: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const $imports = __nccwpck_require__(467);module.exports={name:"simple.art"};module.exports.render=function($data){ 'use strict' $data=$data||{} var $$out='',$escape=$imports.$escape,$V=$data.$V,navs=$data.navs,$each=$imports.$each,$value=$data.$value,$index=$data.$index,response=$data.response $$out+="" $$out+=$escape($V.site.name) $$out+="
" var navs=$V.navs $$out+=" " $each(navs,function($value,$index){ $$out+=" " if($index===0){ $$out+=" Home " }else{ $$out+=" / " $$out+=$escape($value.name) $$out+=" " } $$out+=" " }) $$out+="
" if(response.isList){ $$out+=" " $each($V.list,function($value,$index){ $$out+="
" $$out+=$escape($value.name) $$out+="
" }) $$out+=" " if($V.hasNext){ $$out+="
Next...
" } $$out+=" " }else{ $$out+="
"
$$out+=$escape($V.jsonData)
$$out+="
" } $$out+="
" return $$out } /***/ }), /***/ 529: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const $imports = __nccwpck_require__(467);module.exports={name:"w.w.art"};module.exports.render=function($data){ 'use strict' $data=$data||{} var $$out='',$escape=$imports.$escape,$V=$data.$V,navs=$data.navs,$each=$imports.$each,$value=$data.$value,$index=$data.$index,response=$data.response,type=$data.type,url=$data.url,oUrl=$data.oUrl $$out+="" $$out+=$escape($V.site.name) $$out+="
" if(response.isList){ $$out+="
" if($V.hasPrev){ $$out+=" " }else if($V.hasParent){ $$out+=" " } $$out+=" " $each($V.list,function($value,$index){ $$out+=" " }) $$out+=" " if($V.hasNext){ $$out+=" " } $$out+="
NameTimeSize
👆Previous...
👈..
" $$out+=$escape(($value.type===0?'':'📁') + $value.name) $$out+="" $$out+=$escape($value.time) $$out+="" $$out+=$escape($value.size) $$out+="
👇Next...
" if($V.isEmpty){ $$out+="

Empty Folder!

" } $$out+="
" }else if(response.isFile){ $$out+=" " var type=$V.previewType $$out+=" " var url=$V.downloadUrl $$out+=" " var oUrl=$V.previewHref($V.file,false) $$out+="
下 载
" if(type === 'image'){ $$out+=" \"图片加载失败\" " }else if(type === 'video' || $V.file.name.endsWith('.m3u8')){ $$out+="
" }else if(type === 'audio'){ $$out+=" " }else if(type === 'office'){ $$out+=" " }else if(type==='pdf'){ $$out+="
" }else if(type==='text'){ $$out+="
loading...
" }else if(type==='bigText'){ $$out+="

该文本文件太大, 不支持预览 :-(

" }else{ $$out+="

此格式(" $$out+=$escape($V.file.mime) $$out+=")不支持预览 :-(

" } $$out+="
" }else{ $$out+=" " if($V.hasPassword){ $$out+="
" } $$out+="
" $$out+=$escape(response.message) $$out+="
"
$$out+=$escape($V.jsonData)
$$out+="
" } $$out+="
README
" $$out+=$escape($V.readme) $$out+="
" if($V.readmeUrl){ $$out+=" " } $$out+="
" $$out+=$V.site.html $$out+="
" return $$out } /***/ }), /***/ 463: /***/ ((module) => { module.exports = { render: () => {} }; /***/ }), /***/ 306: /***/ ((module) => { "use strict"; module.exports = JSON.parse('{"author":"ukuq","bugs":{"url":"https://github.com/ukuq/onepoint/issues"},"dependencies":{},"description":"a tiny file index and manage program","devDependencies":{"@vercel/ncc":"^0.28.6","art-template":"^4.13.2","eslint":"^7.16.0","eslint-config-prettier":"^7.1.0","eslint-plugin-prettier":"^3.3.0","html-minifier-terser":"^5.1.1","prettier":"^2.2.1"},"files":["lib"],"homepage":"https://github.com/ukuq/onepoint#readme","keywords":["onepoint","onedrive","google-drive","scf","serverless"],"license":"MIT","main":"lib/app.js","name":"onepoint","prettier":{"printWidth":233,"singleQuote":true,"tabWidth":4,"trailingComma":"es5"},"repository":{"type":"git","url":"git+https://github.com/ukuq/onepoint.git"},"scripts":{"__local_start":"node lib/starters/local-test.js","__pre_commit":"node tmp/pre-commit.js","build:ncc":"node ncc/build.js","format":"eslint \\"**/*.js\\" --fix && prettier \\"**/*.{js,json}\\" --write","format:check":"eslint \\"**/*.js\\" && prettier \\"**/*.{js,json}\\" --check","start":"node lib/starters/node-http.js"},"version":"2.0.1","version2":"210620"}'); /***/ }), /***/ 747: /***/ ((module) => { "use strict"; module.exports = require("fs");; /***/ }), /***/ 605: /***/ ((module) => { "use strict"; module.exports = require("http");; /***/ }), /***/ 211: /***/ ((module) => { "use strict"; module.exports = require("https");; /***/ }), /***/ 761: /***/ ((module) => { "use strict"; module.exports = require("zlib");; /***/ }) /******/ }); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __nccwpck_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ var threw = true; /******/ try { /******/ __webpack_modules__[moduleId](module, module.exports, __nccwpck_require__); /******/ threw = false; /******/ } finally { /******/ if(threw) delete __webpack_module_cache__[moduleId]; /******/ } /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ /******/ /* webpack/runtime/compat */ /******/ /******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";/************************************************************************/ var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. (() => { globalThis.module = {}; globalThis.require = () => 0; globalThis.__dirname = ''; const app = __nccwpck_require__(417); const { P, exposeHeadersWhenProxy, request: _request } = __nccwpck_require__(166); //otherwise, Date.now() is 0 function initApp() { initApp = () => 0; const KVConfig = typeof OPCONFIG === 'undefined' ? null : OPCONFIG; function ensureConfigExist() { if (typeof KVConfig === 'undefined') { throw new Error('KV Namespace not found'); } } async function readConfig() { return KVConfig ? JSON.parse((await KVConfig.get('op-config')) || '{}') : {}; } async function writeConfig(config) { ensureConfigExist(); return KVConfig.put('op-config', JSON.stringify(config)); } const h = '注意,必需新建KV,并将其绑定到对应的 Workers KV Namespace,绑定的名称为OPCONFIG'; app.initialize({ name: 'cf-worker', readConfig, writeConfig, params: [P('x_empty', '', h, 8, 'just let me empty', false, false)], }); } async function handleEvent(event) { initApp(); const request = event.request; const url = new URL(request.url); const h = {}; for (let [k, v] of request.headers) { h[k] = v; } const req = { method: request.method, path: url.pathname, headers: h, body: await request.text(), query: url.search, ip: [request.headers.get('CF-Connecting-IP')], }; return app.handleRequest(req).then((response) => { if (response.callback_down) { const { url, method, headers = {}, body } = response.callback_down; h.range && (headers.range = h.range); return _request.request({ url, method, headers, body, responseType: 'stream' }).then((r) => { const h2 = response.headers; Object.entries(r.headers).forEach(([k, v]) => exposeHeadersWhenProxy(k) && (h2[k] = v)); return new Response(r.data, { status: r.status, headers: h2, }); }); } return new Response(response.body, { status: response.status, headers: response.headers, }); }); } addEventListener('fetch', (event) => { event.respondWith( handleEvent(event).catch((err) => { return new Response( JSON.stringify({ error: err.type || 'UnknownError', data: err.data || {}, msg: err.message, }), { status: err.status || 500, headers: { 'access-control-allow-origin': '*', 'content-type': 'application/json', }, } ); }) ); }); })(); module.exports = __webpack_exports__; /******/ })() ;