hfs 3.3.0-beta3 → 3.3.0-rc5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/admin/assets/{AccountsPage-DB7ljNHT.js → AccountsPage-Cq0xZ11q.js} +2 -2
  2. package/admin/assets/{ArrayField-Qj2iHD7I.js → ArrayField-DlXwGcRi.js} +1 -1
  3. package/admin/assets/{ConfigFilePage-TErmt0PK.js → ConfigFilePage-CS1DHLl9.js} +1 -1
  4. package/admin/assets/{CustomHtmlPage-CVmk-_JS.js → CustomHtmlPage-D2bJwsUf.js} +1 -1
  5. package/admin/assets/{DataTable-DmnQXyFO.js → DataTable--J_wIcuM.js} +1 -1
  6. package/admin/assets/{DateTimeField-BUWd2w9-.js → DateTimeField-DWeCPNja.js} +1 -1
  7. package/admin/assets/{EventManager-9vwKg8as.js → EventManager-DrRWt_JH.js} +1 -1
  8. package/admin/assets/{FileField-DoBaSTxF.js → FileField-mNPkd3y3.js} +1 -1
  9. package/admin/assets/{InternetPage-Biuer1tb.js → InternetPage--PzizUL_.js} +1 -1
  10. package/admin/assets/{LangPage-Vd24DNK5.js → LangPage-B4rQVR1J.js} +1 -1
  11. package/admin/assets/{LogsPage-BdvttEqM.js → LogsPage-Cf8QzZqj.js} +2 -2
  12. package/admin/assets/{MenuButton-CHLgqU5W.js → MenuButton-DMz8eU4k.js} +1 -1
  13. package/admin/assets/{MonitorPage-DlXkZUmT.js → MonitorPage-BfEEqSB9.js} +1 -1
  14. package/admin/assets/{OptionsPage-Zi8FmrjE.js → OptionsPage-Di4sYyHk.js} +1 -1
  15. package/admin/assets/{PluginsPage-BzwEIFt5.js → PluginsPage-C1AwIVck.js} +1 -1
  16. package/admin/assets/{Tabs-CVipqhB9.js → Tabs-B8NzzlRi.js} +1 -1
  17. package/admin/assets/{TextEditor-clbVugYM.js → TextEditor-BF5GhCMi.js} +1 -1
  18. package/admin/assets/{VfsPathField-YUCV9PfL.js → VfsPathField-BKblqejE.js} +1 -1
  19. package/admin/assets/{agentIcons-DW9QViyx.js → agentIcons-xvHQBkKp.js} +1 -1
  20. package/admin/assets/{baseUrl-Do5CYuBZ.js → baseUrl-Cp5EQLCd.js} +1 -1
  21. package/admin/assets/icons-BfdCXZin.js +1 -0
  22. package/admin/assets/{index-Dsq-sVu9.js → index-CSmjBo2G.js} +2 -2
  23. package/admin/assets/{routing-Cjyek7O_.js → routing-BQgmPveQ.js} +1 -1
  24. package/admin/index.html +1 -1
  25. package/frontend/assets/{dist-legacy-BNFW04Ss.js → dist-legacy-BwOLCt69.js} +1 -1
  26. package/frontend/assets/index-legacy-BrUKT6jx.js +1 -0
  27. package/frontend/assets/{lib-legacy-CO5spnaN.js → lib-legacy-Dtus09cI.js} +1 -1
  28. package/frontend/assets/{sha512-legacy-BuJAJxVV.js → sha512-legacy-CBENfTz7.js} +1 -1
  29. package/frontend/index.html +1 -1
  30. package/npm-shrinkwrap.json +135 -85
  31. package/package.json +1 -1
  32. package/plugins/antibrute/plugin.js +23 -14
  33. package/src/api.accounts.js +1 -1
  34. package/src/api.auth.js +1 -0
  35. package/src/api.monitor.js +1 -1
  36. package/src/config.js +7 -6
  37. package/src/cross.js +1 -1
  38. package/src/customHtml.js +1 -6
  39. package/src/frontEndApis.js +2 -1
  40. package/src/log.js +1 -1
  41. package/src/middlewares.js +6 -0
  42. package/src/multipartUpload.js +1 -1
  43. package/src/perm.js +19 -7
  44. package/src/serveFile.js +6 -2
  45. package/src/serveGuiAndSharedFiles.js +1 -1
  46. package/src/serveGuiFiles.js +5 -1
  47. package/src/uploadOwners.js +1 -1
  48. package/src/vfs.js +5 -6
  49. package/src/webdav.js +34 -19
  50. package/src/zip.js +3 -1
  51. package/admin/assets/icons-3rupj9Xr.js +0 -1
  52. package/frontend/assets/index-legacy-2akkos6t.js +0 -1
@@ -16,10 +16,10 @@ exports.configDialog = {
16
16
  maxWidth: 'xs',
17
17
  }
18
18
 
19
- const byIp = {}
20
- const byAccount = {}
21
- const laneByIp = {}
22
- const laneByAccount = {}
19
+ const byIp = new Map()
20
+ const byAccount = new Map()
21
+ const laneByIp = new Map()
22
+ const laneByAccount = new Map()
23
23
  const UNKNOWN_ACCOUNT = 'unknown\t'
24
24
 
25
25
  exports.init = api => {
@@ -107,7 +107,12 @@ exports.init = api => {
107
107
  })
108
108
 
109
109
  function getRecord(container, key) {
110
- return container[key] ||= { failures: 0, next: 0, waiting: 0 }
110
+ let rec = container.get(key)
111
+ if (!rec) {
112
+ rec = { failures: 0, next: 0, waiting: 0 }
113
+ container.set(key, rec)
114
+ }
115
+ return rec
111
116
  }
112
117
 
113
118
  function increasePenalty(rec, now) {
@@ -124,7 +129,7 @@ exports.init = api => {
124
129
  // keep records while there are in-flight admissions, otherwise later releases may touch deleted state
125
130
  if (rec.waiting)
126
131
  return armCleanup(records, key, rec)
127
- delete records[key]
132
+ records.delete(key)
128
133
  }, 24 * HOUR) // no memory leak
129
134
  }
130
135
 
@@ -138,7 +143,12 @@ exports.init = api => {
138
143
  }
139
144
 
140
145
  function getLane(container, key) {
141
- return container[key] ||= makeQ(1)
146
+ let lane = container.get(key)
147
+ if (!lane) {
148
+ lane = makeQ(1)
149
+ container.set(key, lane)
150
+ }
151
+ return lane
142
152
  }
143
153
 
144
154
  function runInLane(q, job) {
@@ -151,13 +161,13 @@ exports.init = api => {
151
161
  }
152
162
 
153
163
  function dropLaneIfIdle(container, key) {
154
- const q = container[key]
164
+ const q = container.get(key)
155
165
  if (q?.isWorking() || q?.queueSize()) return
156
- delete container[key]
166
+ container.delete(key)
157
167
  }
158
168
 
159
169
  function resetRecord(container, key) {
160
- const rec = container[key]
170
+ const rec = container.get(key)
161
171
  if (!rec) return
162
172
  if (rec.waiting) {
163
173
  // successful login must clear penalties without dropping admission counters still needed by concurrent requests
@@ -165,14 +175,13 @@ exports.init = api => {
165
175
  rec.next = 0
166
176
  return
167
177
  }
168
- delete container[key]
178
+ container.delete(key)
169
179
  }
170
180
 
171
181
  function getAccountKey(username) {
172
182
  // fold unknown usernames together to avoid unbounded memory growth from random names
173
- if (!username || !api.getAccount(String(username)))
174
- return UNKNOWN_ACCOUNT
175
- return String(username).toLowerCase()
183
+ const account = username && api.getAccount(String(username))
184
+ return account ? account.username : UNKNOWN_ACCOUNT
176
185
  }
177
186
 
178
187
  function isExcluded(ip) {
@@ -61,7 +61,7 @@ exports.default = {
61
61
  return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST);
62
62
  await (0, perm_1.updateAccount)(acc, (0, api_vfs_1.pickProps)(changes, ALLOWED_KEYS));
63
63
  if (changes.username && ctx.session?.username === (0, perm_1.normalizeUsername)(username)) // update session if necessary
64
- ctx.session.username = (0, perm_1.normalizeUsername)(changes.username);
64
+ ctx.session.username = acc.username;
65
65
  return lodash_1.default.pick(acc, 'username');
66
66
  },
67
67
  async add_account({ overwrite, username, ...rest }) {
package/src/api.auth.js CHANGED
@@ -80,6 +80,7 @@ exports.authApis = {
80
80
  const sid = (0, node_crypto_1.randomUUID)();
81
81
  ongoingLogins[sid] = srpServer;
82
82
  setTimeout(() => delete ongoingLogins[sid], 60_000); // client must complete api sequence (loginSrp2) within 1 minute or will be discarded to avoid memory leaks
83
+ // 60-second expiry bounded 5k challenges to ~37 MB in a local saturation test, so an additional cap isn't justified
83
84
  ctx.session.loggingIn = { username, sid }; // temporarily store until process is complete
84
85
  return rest;
85
86
  }
@@ -108,7 +108,7 @@ function inferOperation(ctx) {
108
108
  : s.uploadPath ? { op: 'upload', path: (0, misc_1.safeDecodeURIComponent)(s.uploadPath) }
109
109
  : {
110
110
  op: !s.considerAsGui && (ctx.state.archive || ctx.state.vfsNode) ? 'download' : undefined,
111
- path: (0, misc_1.safeDecodeURIComponent)(ctx.originalUrl),
111
+ path: (0, misc_1.safeDecodeURIComponent)(s.safeUrl),
112
112
  },
113
113
  opProgress: lodash_1.default.isNumber(s.opProgress) ? lodash_1.default.round(s.opProgress, 3) : undefined,
114
114
  opTotal: s.opTotal,
package/src/config.js CHANGED
@@ -80,13 +80,13 @@ function defineConfig(k, defaultValue, compiler) {
80
80
  },
81
81
  sub(cb) {
82
82
  if (started) // initial event already passed, we'll make the first call
83
- cb(getConfig(k), { k, was: defaultValue, defaultValue, version: configVersion.compiled(), object });
83
+ cb(getConfig(k), { k, was: defaultValue, defaultValue, version: configVersion.compiled(), set, object });
84
84
  return events_1.default.on(CONFIG_CHANGE_EVENT_PREFIX + k, (v, was, version, onlyCompileChanged) => {
85
85
  if (stack.includes(cb))
86
86
  return; // avoid infinite loop in case a subscriber changes the value
87
87
  stack.push(cb);
88
88
  try {
89
- return cb(v, { k, was, version, defaultValue, object, onlyCompileChanged });
89
+ return cb(v, { k, was, version, set, defaultValue, object, onlyCompileChanged });
90
90
  }
91
91
  finally {
92
92
  stack.pop();
@@ -109,7 +109,8 @@ function defineConfig(k, defaultValue, compiler) {
109
109
  },
110
110
  dontStore() { dontStore.push(k); },
111
111
  };
112
- let compiled = compiler?.(defaultValue, { k, version: exports.currentVersion, defaultValue, object });
112
+ const set = object.set.bind(object);
113
+ let compiled = compiler?.(defaultValue, { k, version: exports.currentVersion, set, defaultValue, object });
113
114
  if (compiler)
114
115
  object.sub((v, more) => {
115
116
  if (!more.onlyCompileChanged)
@@ -154,13 +155,13 @@ async function setConfig(newCfg, save) {
154
155
  return;
155
156
  }
156
157
  // first time we emit also for the default values
157
- await Promise.allSettled(Object.keys(configProps).map(k => newCfg.hasOwnProperty(k) || apply(k, undefined, true)));
158
+ await Promise.allSettled(Object.keys(configProps).map(k => newCfg.hasOwnProperty(k) || apply(k, undefined)));
158
159
  started = true;
159
160
  events_1.default.emit('configReady', startedWithoutConfig);
160
161
  if (version?.valueOf() !== const_1.VERSION) // be sure to save the new version in the file
161
162
  (0, exports.saveConfigAsap)();
162
- function apply(k, newV, isDefault = false) {
163
- return setConfig1(k, newV, save === undefined, argCfg && k in argCfg || isDefault ? exports.currentVersion : version);
163
+ function apply(k, newV) {
164
+ return setConfig1(k, newV, save === undefined, !lodash_1.default.has(argCfg, k) && version || exports.currentVersion);
164
165
  }
165
166
  }
166
167
  async function setConfig1(k, newV, saveChanges = true, valueVersion) {
package/src/cross.js CHANGED
@@ -356,7 +356,7 @@ function randomId(len = 10) {
356
356
  .replace(/l/g, 'L'); // avoid confusion reading l1
357
357
  }
358
358
  function objRenameKey(o, from, to) {
359
- if (!o || !o.hasOwnProperty(from) || from === to)
359
+ if (!o || !Object.hasOwn(o, from) || from === to)
360
360
  return;
361
361
  o[to] = o[from];
362
362
  delete o[from];
package/src/customHtml.js CHANGED
@@ -11,7 +11,6 @@ exports.saveCustomHtml = saveCustomHtml;
11
11
  const misc_1 = require("./misc");
12
12
  const watchLoad_1 = require("./watchLoad");
13
13
  const config_1 = require("./config");
14
- const promises_1 = require("fs/promises");
15
14
  const plugins_1 = require("./plugins");
16
15
  const lodash_1 = __importDefault(require("lodash"));
17
16
  const FILE = 'custom.html';
@@ -50,9 +49,5 @@ function getAllSections() {
50
49
  }
51
50
  async function saveCustomHtml(sections) {
52
51
  const text = Object.entries(sections).filter(([k, v]) => v?.trim()).map(([k, v]) => `[${k}]\n${v}\n\n`).join('');
53
- await (0, promises_1.writeFile)(FILE, text);
54
- exports.customHtml.sections.clear();
55
- for (const [k, v] of Object.entries(sections))
56
- if (v)
57
- exports.customHtml.sections.set(k, v);
52
+ await exports.customHtml.save(text, { reparse: true });
58
53
  }
@@ -80,6 +80,7 @@ exports.frontEndApis = {
80
80
  return new apiMiddleware_1.ApiError(err);
81
81
  try {
82
82
  await (0, promises_1.mkdir)((0, path_1.join)(parentNode.source, name));
83
+ await (0, uploadOwners_1.setUploadOwner)((0, misc_1.join)(uri, (0, misc_1.pathEncode)(name)), ctx);
83
84
  return {};
84
85
  }
85
86
  catch (e) {
@@ -219,7 +220,7 @@ async function requestedRename(node, newName, ctx, uri = ctx.path) {
219
220
  else {
220
221
  if (!node.source)
221
222
  throw new apiMiddleware_1.ApiError(const_1.HTTP_FAILED_DEPENDENCY);
222
- const destNode = await (0, vfs_1.urlToNode)((0, misc_1.pathEncode)(newName), ctx, node.parent);
223
+ const destNode = await (0, vfs_1.urlToNode)((0, misc_1.pathEncode)(newName), ctx, node.parent, { includeHidden: true });
223
224
  if (destNode && (0, vfs_1.statusCodeForMissingPerm)(destNode, 'can_delete', ctx)) // if destination exists, you need delete permission
224
225
  throw new apiMiddleware_1.ApiError(ctx.status);
225
226
  try {
package/src/log.js CHANGED
@@ -169,7 +169,7 @@ const logMw = async (ctx, next) => {
169
169
  const date = `${a[2]}/${a[1]}/${a[3]}:${a[4]} ${a[5]?.slice(3)}`;
170
170
  const user = (0, auth_1.getCurrentUsername)(ctx) || userAtStart;
171
171
  const length = ctx.state.length ?? ctx.length;
172
- const uri = ctx.originalUrl;
172
+ const uri = ctx.state.safeUrl;
173
173
  const duration = (Number(reqEnd) - Number(reqStart)) / 1000;
174
174
  ctx.logExtra(ctx.vfsNode && {
175
175
  speed: Math.round(length / duration),
@@ -92,6 +92,12 @@ function getProxyDetected() {
92
92
  const prepareState = async (ctx, next) => {
93
93
  // normalize once so auth, filters and logging agree on the same client address
94
94
  ctx.request.ip = (0, connections_1.normalizeIp)(ctx.ip);
95
+ ctx.state.safeUrl = ctx.originalUrl;
96
+ if (ctx.query.login) {
97
+ const query = new URLSearchParams(ctx.querystring);
98
+ query.set('login', '...');
99
+ ctx.state.safeUrl = `${ctx.path}?${query}`;
100
+ }
95
101
  const s = ctx.session;
96
102
  if (s?.username) {
97
103
  if (s.ts < auth_1.invalidateSessionBefore.get(s?.username))
@@ -77,7 +77,7 @@ async function handleMultipartUpload(ctx, node) {
77
77
  const prefix = (0, path_1.dirname)(fn.replaceAll('\\', '/'));
78
78
  if (prefix === '.') // no subdir
79
79
  return false;
80
- const subfolderNode = await (0, vfs_1.urlToNode)(prefix + '/', ctx, node, true); // final slash = explicitly a folder even if it doesn't exist on disk
80
+ const subfolderNode = await (0, vfs_1.urlToNode)(prefix + '/', ctx, node, { allowMissing: true }); // final slash = explicitly a folder even if it doesn't exist on disk
81
81
  return subfolderNode && !(0, vfs_1.hasPermission)(subfolderNode, 'can_upload', ctx);
82
82
  }
83
83
  }
package/src/perm.js CHANGED
@@ -54,7 +54,8 @@ function getUsernames() {
54
54
  function getAccount(username, normalize = true) {
55
55
  if (normalize)
56
56
  username = normalizeUsername(username);
57
- return username ? exports.accounts.get()[username] : undefined;
57
+ const all = exports.accounts.get();
58
+ return username && Object.hasOwn(all, username) ? all[username] : undefined;
58
59
  }
59
60
  function saveSrpInfo(account, salt, verifier) {
60
61
  account.srp = String(salt) + '|' + String(verifier);
@@ -79,10 +80,13 @@ async function updateAccount(account, change) {
79
80
  await change?.(account);
80
81
  else {
81
82
  const u = normalizeUsername(change.username || '');
82
- if (!u)
83
+ if (!u || isPrototypeKey(u))
83
84
  delete change.username;
84
- else if (u !== usernameWas && getAccount(u))
85
- throw "username already exists";
85
+ else {
86
+ if (u !== usernameWas && getAccount(u))
87
+ throw "username already exists";
88
+ change.username = u;
89
+ }
86
90
  Object.assign(account, lodash_1.default.mapValues(change, x => x || undefined));
87
91
  }
88
92
  for (const [k, v] of (0, misc_1.typedEntries)(account))
@@ -98,7 +102,7 @@ async function updateAccount(account, change) {
98
102
  if (account.belongs) {
99
103
  account.belongs = (0, misc_1.wantArray)(account.belongs);
100
104
  lodash_1.default.remove(account.belongs, b => {
101
- if (exports.accounts.get().hasOwnProperty(b))
105
+ if (Object.hasOwn(exports.accounts.get(), b))
102
106
  return;
103
107
  console.error(`Account ${username} belongs to non-existing ${b}`);
104
108
  return true;
@@ -118,6 +122,11 @@ exports.accounts.sub(lodash_1.default.debounce(obj => {
118
122
  // consider some validation here, in case of manual edit of the config
119
123
  lodash_1.default.each(obj, (rec, k) => {
120
124
  const norm = normalizeUsername(k);
125
+ if (isPrototypeKey(norm)) {
126
+ delete obj[k];
127
+ saveAccountsAsap();
128
+ return;
129
+ }
121
130
  if (rec?.username !== norm) {
122
131
  if (!rec) // an empty object in yaml is parsed as null
123
132
  rec = obj[norm] = { username: norm };
@@ -154,11 +163,14 @@ exports.accounts.sub(lodash_1.default.debounce(obj => {
154
163
  function normalizeUsername(username) {
155
164
  return username.toLocaleLowerCase();
156
165
  }
166
+ function isPrototypeKey(username) {
167
+ return username === '__proto__' || username === 'constructor';
168
+ }
157
169
  function renameAccount(from, to) {
158
170
  from = normalizeUsername(from);
159
171
  const as = exports.accounts.get();
160
172
  to = normalizeUsername(to);
161
- if (!to || !as[from] || as[to])
173
+ if (!to || isPrototypeKey(to) || !Object.hasOwn(as, from) || Object.hasOwn(as, to))
162
174
  return false;
163
175
  if (to === from)
164
176
  return true;
@@ -177,7 +189,7 @@ function renameAccount(from, to) {
177
189
  }
178
190
  function addAccount(username, props, updateExisting = false) {
179
191
  username = normalizeUsername(username);
180
- if (!username)
192
+ if (!username || isPrototypeKey(username))
181
193
  return;
182
194
  let account = getAccount(username, false);
183
195
  if (account && !updateExisting)
package/src/serveFile.js CHANGED
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.forceDownload = forceDownload;
8
8
  exports.disposition = disposition;
9
9
  exports.serveFileNode = serveFileNode;
10
+ exports.enforceDownloadLimits = enforceDownloadLimits;
10
11
  exports.serveFile = serveFile;
11
12
  exports.monitorAsDownload = monitorAsDownload;
12
13
  exports.applyRange = applyRange;
@@ -63,8 +64,11 @@ async function serveFileNode(ctx, node) {
63
64
  // legacy clients often send Accept: */* for archive downloads, so the served mime is a safer signal than request headers here
64
65
  : GUI_ASSET_MIME.test(mimeString || mime_types_1.default.lookup(source || '') || ''));
65
66
  await serveFile(ctx, source || '', mimeString);
66
- if (await maxDownloadsPerAccount(ctx) === undefined) // returning false will not execute other limits
67
- await maxDownloads(ctx) || await maxDownloadsPerIp(ctx);
67
+ await enforceDownloadLimits(ctx);
68
+ }
69
+ async function enforceDownloadLimits(ctx) {
70
+ return await maxDownloadsPerAccount(ctx)
71
+ ?? (await maxDownloads(ctx) || await maxDownloadsPerIp(ctx)); // a configured account limit overrides the global and IP limits
68
72
  }
69
73
  const mimeCfg = (0, config_1.defineConfig)(misc_1.CFG.mime, {}, obj => {
70
74
  const matchers = Object.keys(obj).map(k => (0, misc_1.makeMatcher)(k));
@@ -71,7 +71,7 @@ const serveSharedFiles = async (ctx, next) => {
71
71
  const decPath = (0, misc_1.safeDecodeURIComponent)(path, '');
72
72
  const fn = (0, path_1.basename)(decPath);
73
73
  const folderUri = (0, misc_1.pathEncode)((0, path_1.dirname)(decPath)); // re-encode to get readable urls
74
- const folder = await (0, vfs_1.urlToNode)(folderUri, ctx, vfs_1.vfs.compiled(), true); // we don't require the folder to already exist, but to be mapped on disk AND to have proper permissions
74
+ const folder = await (0, vfs_1.urlToNode)(folderUri, ctx, vfs_1.vfs.compiled(), { allowMissing: true }); // we don't require the folder to already exist, but to be mapped on disk AND to have proper permissions
75
75
  if (!folder)
76
76
  return (0, errorPages_1.sendErrorPage)(ctx, cross_const_1.HTTP_NOT_FOUND);
77
77
  ctx.state.uploadPath = decPath;
@@ -22,10 +22,14 @@ const lang_1 = require("./lang");
22
22
  const upload_1 = require("./upload");
23
23
  const icons_1 = require("./icons");
24
24
  const middlewares_1 = require("./middlewares");
25
+ (0, config_1.defineConfig)(misc_1.CFG.menu_at_top, misc_1.FRONTEND_OPTIONS[misc_1.CFG.menu_at_top]).sub((v, { version, set }) => {
26
+ if (!v && version?.olderThan('3.3.0-alpha1')) // preserve the layout used before this option existed for upgraded installations
27
+ set(true);
28
+ });
25
29
  const size1024 = (0, config_1.defineConfig)(misc_1.CFG.size_1024, false, x => misc_1.formatBytes.k = x ? 1024 : 1000); // we both configure formatBytes, and also provide a compiled version (number instead of boolean)
26
30
  const splitUploads = (0, config_1.defineConfig)(misc_1.CFG.split_uploads, 0);
27
31
  exports.logGui = (0, config_1.defineConfig)(misc_1.CFG.log_gui, false);
28
- lodash_1.default.each(misc_1.FRONTEND_OPTIONS, (v, k) => (0, config_1.defineConfig)(k, v)); // define default values
32
+ lodash_1.default.each(misc_1.FRONTEND_OPTIONS, (v, k) => k !== misc_1.CFG.menu_at_top && (0, config_1.defineConfig)(k, v)); // define default values
29
33
  function serveStatic(uri) {
30
34
  const folder = (const_1.DEV ? 'dist/' : '') + uri.slice(2, -1);
31
35
  const root = (0, path_1.join)(__dirname, '..', folder);
@@ -88,7 +88,7 @@ function getSessionId(ctx) {
88
88
  return ctx.session.sessionId ||= (0, misc_1.randomId)(30);
89
89
  }
90
90
  function cleanVfsPath(path) {
91
- return '/' + path.replace(/^\/+|\/+$/g, '');
91
+ return (0, misc_1.pathDecodeSegments)('/' + path.replace(/^\/+|\/+$/g, ''), misc_1.pathEncode);
92
92
  }
93
93
  function isSameOrInside(parent, path) {
94
94
  return path === parent || path.startsWith(parent + '/');
package/src/vfs.js CHANGED
@@ -108,8 +108,7 @@ async function applyParentToChild(child, parent, name) {
108
108
  inheritFromParent(ret);
109
109
  return ret;
110
110
  }
111
- async function urlToNode(url, ctx, parent = exports.vfs.compiled(), allowMissing // true means missing path segments still resolve to temporary nodes with a computed source path
112
- ) {
111
+ async function urlToNode(url, ctx, parent = exports.vfs.compiled(), options = {}) {
113
112
  let initialSlashes = 0;
114
113
  while (url[initialSlashes] === '/')
115
114
  initialSlashes++;
@@ -122,16 +121,16 @@ async function urlToNode(url, ctx, parent = exports.vfs.compiled(), allowMissing
122
121
  return;
123
122
  const hasTrailingSlash = url.endsWith('/');
124
123
  const rest = nextSlash < 0 ? '' : url.slice(nextSlash + 1, hasTrailingSlash ? -1 : undefined);
125
- const assumeFolder = allowMissing && (rest > '' || hasTrailingSlash);
124
+ const assumeFolder = options.allowMissing && (rest > '' || hasTrailingSlash);
126
125
  const ret = await getNodeByName(name, parent, assumeFolder);
127
126
  if (!ret)
128
127
  return;
129
128
  setVfsPath(ret, name, parent);
130
129
  if (rest || ret?.original)
131
- return urlToNode(rest, ctx, ret, allowMissing);
130
+ return urlToNode(rest, ctx, ret, options);
132
131
  if (ret.source)
133
- if (!showHiddenFiles.get() && await isHiddenFile(ret.source)
134
- || !allowMissing && await setIsFolder(ret) === undefined) // undefined = not found on disk
132
+ if (!options.includeHidden && !showHiddenFiles.get() && await isHiddenFile(ret.source)
133
+ || !options.allowMissing && await setIsFolder(ret) === undefined) // undefined = not found on disk
135
134
  return;
136
135
  return ret;
137
136
  }
package/src/webdav.js CHANGED
@@ -53,20 +53,22 @@ const WINDOWS_FILE_ATTRIBUTE_FLAGS = {
53
53
  const canOverwrite = new Set();
54
54
  const locks = new Map();
55
55
  function releaseWebdavLock(path) {
56
- const lock = locks.get(path);
56
+ const key = webdavPathKey(path);
57
+ const lock = locks.get(key);
57
58
  if (!lock)
58
59
  return false;
59
60
  clearTimeout(lock.timeout);
60
- locks.delete(path);
61
+ locks.delete(key);
61
62
  return true;
62
63
  }
63
64
  async function isLocked(path, ctx) {
64
- const lock = locks.get(path);
65
+ const key = webdavPathKey(path);
66
+ const lock = locks.get(key);
65
67
  if (!lock)
66
68
  return false;
67
69
  // if the resource is gone, keeping the lock only creates fake 423 responses
68
- if (!await (0, vfs_1.urlToNode)(path, ctx)) {
69
- releaseWebdavLock(path);
70
+ if (!await (0, vfs_1.urlToNode)(key, ctx)) {
71
+ releaseWebdavLock(key);
70
72
  return false;
71
73
  }
72
74
  const ifHeader = ctx.get('If');
@@ -81,6 +83,10 @@ function hasToken(header, token) {
81
83
  return false;
82
84
  return header.includes(`<${token}>`) || header.split(/[,;\s]+/).includes(token);
83
85
  }
86
+ function webdavPathKey(path) {
87
+ const key = (0, cross_1.pathEncode)((0, cross_1.safeDecodeURIComponent)(path, ''));
88
+ return (0, misc_1.hasDirTraversal)(key) ? '' : key;
89
+ }
84
90
  function getWebdavUsername(ctx) {
85
91
  return (0, auth_1.getCurrentUsername)(ctx) || '';
86
92
  }
@@ -107,6 +113,9 @@ const webdav = async (ctx, next) => {
107
113
  webdavDetectedAgents.try(webdavAgentKey(ctx, ua), () => true);
108
114
  if (isCorsPreflight)
109
115
  return next();
116
+ const pathKey = webdavPathKey(path); // state must converge for equivalent encodings without changing client-visible paths
117
+ if (!pathKey && (isWebdavAuthRequest || ctx.method === 'PUT' || ctx.method === 'DELETE'))
118
+ return ctx.status = cross_1.HTTP_BAD_REQUEST;
110
119
  if (isWebdavAuthRequest && shouldChallengeWebdav())
111
120
  return;
112
121
  if (ctx.method === 'OPTIONS')
@@ -143,7 +152,7 @@ const webdav = async (ctx, next) => {
143
152
  async function handlePut() {
144
153
  if (await isLocked(path, ctx))
145
154
  return;
146
- const overwriteGraceKey = path + (0, cross_1.prefix)('|', (0, auth_1.getCurrentUsername)(ctx)); // bind temporary overwrite grace to the authenticated user so accounts cannot reuse each other's grace window
155
+ const overwriteGraceKey = pathKey + (0, cross_1.prefix)('|', (0, auth_1.getCurrentUsername)(ctx)); // bind temporary overwrite grace to the authenticated user so accounts cannot reuse each other's grace window
147
156
  // Finder first creates an empty file (a test?) then wants to overwrite it, which requires deletion permission, but the user may not have it, causing a renamed upload. To solve, so we give it special permission for a few seconds.
148
157
  const x = ctx.get('x-expected-entity-length'); // field used by Finder's webdav on actual upload, after
149
158
  if (isKnownWebdavAgent && canOverwrite.has(overwriteGraceKey)) {
@@ -160,7 +169,7 @@ const webdav = async (ctx, next) => {
160
169
  if (isKnownWebdavAgent)
161
170
  ctx.query.existing ??= 'overwrite'; // with webdav this is our default
162
171
  await next();
163
- if (isKnownWebdavAgent && ctx.body?.uri === path) // the upload middleware reports the final uri that can be different from the initial request
172
+ if (isKnownWebdavAgent && ctx.body?.uri && webdavPathKey(ctx.body.uri) === pathKey) // the upload middleware reports the final uri that can be different from the initial request
164
173
  allowWebdavOverwrite(overwriteGraceKey);
165
174
  }
166
175
  async function handleMkcol() {
@@ -195,27 +204,33 @@ const webdav = async (ctx, next) => {
195
204
  setWebdavHeaders();
196
205
  if (await isLocked(path, ctx))
197
206
  return;
198
- const node = await (0, vfs_1.urlToNode)(path, ctx);
207
+ const node = await (0, vfs_1.urlToNode)(pathKey, ctx);
199
208
  if (!node)
200
209
  return next();
201
210
  let dest = ctx.get('destination');
202
211
  const i = dest.indexOf('//');
203
212
  if (i >= 0)
204
213
  dest = dest.slice(dest.indexOf('/', i + 2));
205
- dest = (0, cross_1.join)(ctx.state.root || '', dest); // on Windows, we must use / as the delimiter to be able to compare with `path` below
214
+ dest = webdavPathKey((0, cross_1.join)(ctx.state.root || '', dest)); // on Windows, we must use / as the delimiter to compare URL paths
215
+ if (!dest)
216
+ return ctx.status = cross_1.HTTP_BAD_REQUEST;
206
217
  if (await isLocked(dest, ctx))
207
218
  return;
208
- if ((0, path_1.dirname)(path) === (0, path_1.dirname)(dest)) // rename case. `path` is is encoded, so we test before decoding `dest`
219
+ if ((0, path_1.dirname)(pathKey) === (0, path_1.dirname)(dest))
209
220
  try {
210
221
  // decode the single path segment so reserved chars like %2C become their real name on rename
211
- await (0, frontEndApis_1.requestedRename)(node, (0, cross_1.safeDecodeURIComponent)((0, path_1.basename)(dest), ''), ctx, path);
222
+ await (0, frontEndApis_1.requestedRename)(node, (0, cross_1.safeDecodeURIComponent)((0, path_1.basename)(dest), ''), ctx, pathKey);
212
223
  releaseWebdavLock(path); // RFC 4918 says MOVE must not carry locks to destination, so clear source lock on success
213
224
  return ctx.status = cross_1.HTTP_CREATED;
214
225
  }
215
226
  catch (e) {
216
227
  return ctx.status = e.status || cross_1.HTTP_SERVER_ERROR;
217
228
  }
218
- const moveRes = await (0, frontEndApis_1.moveFiles)([path], (0, path_1.dirname)(dest), ctx);
229
+ const actualDest = (0, cross_1.join)((0, path_1.dirname)(dest), (0, path_1.basename)(pathKey));
230
+ // moveFiles keeps the source basename for cross-directory moves, so check the lock it will actually touch
231
+ if (actualDest !== dest && await isLocked(actualDest, ctx))
232
+ return;
233
+ const moveRes = await (0, frontEndApis_1.moveFiles)([pathKey], (0, path_1.dirname)(dest), ctx);
219
234
  if (moveRes instanceof Error)
220
235
  return ctx.status = moveRes.status || cross_1.HTTP_SERVER_ERROR;
221
236
  const err = moveRes?.errors?.[0];
@@ -234,7 +249,7 @@ const webdav = async (ctx, next) => {
234
249
  async function handleUnlock() {
235
250
  setWebdavHeaders();
236
251
  const x = ctx.get(TOKEN_HEADER).slice(1, -1);
237
- const lock = locks.get(path);
252
+ const lock = locks.get(pathKey);
238
253
  if (x !== lock?.token)
239
254
  return ctx.status = cross_1.HTTP_BAD_REQUEST;
240
255
  // with force_webdav_login disabled a client may silently fall back to anonymous; keep lock ownership on the original username
@@ -253,7 +268,7 @@ const webdav = async (ctx, next) => {
253
268
  const permissionNode = node || await (0, vfs_1.urlToNode)((0, path_1.dirname)(path), ctx);
254
269
  if (!permissionNode)
255
270
  return ctx.status = cross_1.HTTP_CONFLICT;
256
- const missingWritePerm = node && canOverwrite.has(path + (0, cross_1.prefix)('|', (0, auth_1.getCurrentUsername)(ctx))) ? 0
271
+ const missingWritePerm = node && canOverwrite.has(pathKey + (0, cross_1.prefix)('|', (0, auth_1.getCurrentUsername)(ctx))) ? 0
257
272
  : (0, vfs_1.statusCodeForMissingPerm)(permissionNode, node ? 'can_delete' : 'can_upload', ctx);
258
273
  if (missingWritePerm) {
259
274
  if (ctx.status === cross_1.HTTP_UNAUTHORIZED)
@@ -268,7 +283,7 @@ const webdav = async (ctx, next) => {
268
283
  // Finder and similar clients refresh an existing lock by sending LOCK without a body
269
284
  if (!token)
270
285
  return ctx.status = cross_1.HTTP_BAD_REQUEST;
271
- const lock = locks.get(path);
286
+ const lock = locks.get(pathKey);
272
287
  if (token !== lock?.token)
273
288
  return ctx.status = cross_1.HTTP_PRECONDITION_FAILED;
274
289
  // same-token refresh from another username would make abandoned locks effectively persistent
@@ -278,7 +293,7 @@ const webdav = async (ctx, next) => {
278
293
  clearTimeout(lock.timeout);
279
294
  lock.timeout = setTimeout(() => releaseWebdavLock(path), seconds * 1000);
280
295
  lock.seconds = seconds;
281
- locks.set(path, lock);
296
+ locks.set(pathKey, lock);
282
297
  ctx.set(TOKEN_HEADER, lock.token);
283
298
  ctx.body = renderLockResponse(lock.token, lock.seconds);
284
299
  return;
@@ -292,11 +307,11 @@ const webdav = async (ctx, next) => {
292
307
  return ctx.status = cross_1.HTTP_CONFLICT;
293
308
  if (scope !== 'exclusive' || type !== 'write')
294
309
  return ctx.status = cross_1.HTTP_CONFLICT;
295
- if (locks.has(path))
310
+ if (locks.has(pathKey))
296
311
  return ctx.status = cross_1.HTTP_LOCKED;
297
312
  const newToken = 'urn:uuid:' + (0, node_crypto_1.randomUUID)();
298
313
  const timeout = setTimeout(() => releaseWebdavLock(path), seconds * 1000);
299
- locks.set(path, { token: newToken, timeout, seconds, username: getWebdavUsername(ctx) });
314
+ locks.set(pathKey, { token: newToken, timeout, seconds, username: getWebdavUsername(ctx) });
300
315
  ctx.set(TOKEN_HEADER, newToken);
301
316
  ctx.body = renderLockResponse(newToken, seconds);
302
317
  }
@@ -365,7 +380,7 @@ const webdav = async (ctx, next) => {
365
380
  return ctx.status = cross_1.HTTP_BAD_REQUEST;
366
381
  const statuses = [];
367
382
  for (const prop of props)
368
- statuses.push({ prop: prop.name, status: await applyProppatchProp(prop, node, path, ctx) });
383
+ statuses.push({ prop: prop.name, status: await applyProppatchProp(prop, node, pathKey, ctx) });
369
384
  const outPath = webdavHrefPath(path, node, ctx);
370
385
  ctx.type = 'xml';
371
386
  ctx.status = 207;
package/src/zip.js CHANGED
@@ -82,6 +82,9 @@ async function zipStreamFromFolder(node, ctx) {
82
82
  catch { }
83
83
  });
84
84
  const zip = new QuickZipStream_1.QuickZipStream(mappedWalker);
85
+ ctx.body = zip;
86
+ if (await (0, serveFile_1.enforceDownloadLimits)(ctx))
87
+ return;
85
88
  const time = 1000 * zipSeconds.get();
86
89
  const size = await zip.calculateSize(time);
87
90
  const range = (0, serveFile_1.applyRange)(ctx, size); // keep var size as ctx.response.length won't preserve a NaN
@@ -89,7 +92,6 @@ async function zipStreamFromFolder(node, ctx) {
89
92
  return;
90
93
  if (range)
91
94
  zip.applyRange(range.start, range.end);
92
- ctx.body = zip;
93
95
  ctx.req.on('close', () => zip.destroy());
94
96
  ctx.state.archive = 'zip';
95
97
  (0, serveFile_1.monitorAsDownload)(ctx, size, range?.start);
@@ -1 +0,0 @@
1
- import{Xi as e,ga as t}from"./index-Dsq-sVu9.js";var n=t(),r=e((0,n.jsx)(`path`,{d:`M10 6 8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z`}),`ChevronRight`),i=e((0,n.jsx)(`path`,{d:`M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6zM19 4h-3.5l-1-1h-5l-1 1H5v2h14z`}),`Delete`),a=e((0,n.jsx)(`path`,{d:`M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m0 18c-4.42 0-8-3.58-8-8 0-1.85.63-3.55 1.69-4.9L16.9 18.31C15.55 19.37 13.85 20 12 20m6.31-3.1L7.1 5.69C8.45 4.63 10.15 4 12 4c4.42 0 8 3.58 8 8 0 1.85-.63 3.55-1.69 4.9`}),`DoNotDisturb`),o=e((0,n.jsx)(`path`,{d:`M16.59 8.59 12 13.17 7.41 8.59 6 10l6 6 6-6z`}),`ExpandMore`),s=e((0,n.jsx)(`path`,{d:`M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5s-3 1.34-3 3 1.34 3 3 3m-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5 5 6.34 5 8s1.34 3 3 3m0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5m8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5`}),`Group`),c=e((0,n.jsx)(`path`,{d:`M17 10.43V2H7v8.43c0 .35.18.68.49.86l4.18 2.51-.99 2.34-3.41.29 2.59 2.24L9.07 22 12 20.23 14.93 22l-.78-3.33 2.59-2.24-3.41-.29-.99-2.34 4.18-2.51c.3-.18.48-.5.48-.86m-4 1.8-1 .6-1-.6V3h2z`}),`MilitaryTech`),l=e((0,n.jsx)(`path`,{d:`M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4m0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4`}),`Person`),u=e((0,n.jsx)(`path`,{d:`M15 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4m-9-2V7H4v3H1v2h3v3h2v-3h3v-2zm9 4c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4`}),`PersonAdd`),d=e([(0,n.jsx)(`path`,{d:`M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2M12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8`},`0`),(0,n.jsx)(`path`,{d:`M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z`},`1`)],`Schedule`),f=e([(0,n.jsx)(`path`,{d:`M15 2h-3.5l-1-1h-5l-1 1H1v2h14zm1 7c-.7 0-1.37.1-2 .29V5H2v12c0 1.1.9 2 2 2h5.68c1.12 2.36 3.53 4 6.32 4 3.87 0 7-3.13 7-7s-3.13-7-7-7m0 12c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5`},`0`),(0,n.jsx)(`path`,{d:`M16.5 12H15v5l3.6 2.1.8-1.2-2.9-1.7z`},`1`)],`AutoDelete`),p=e((0,n.jsx)(`path`,{d:`M5 20h14v-2H5zm0-10h4v6h6v-6h4l-7-7z`}),`Upload`),m=e((0,n.jsx)(`path`,{d:`M3 17.25V21h3.75L17.81 9.94l-3.75-3.75zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34a.996.996 0 0 0-1.41 0l-1.83 1.83 3.75 3.75z`}),`Edit`),h=e((0,n.jsx)(`path`,{d:`M5 20h14v-2H5zM19 9h-4V3H9v6H5l7 7z`}),`Download`),g=e((0,n.jsx)(`path`,{d:`M20 13H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1M7 19c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2M20 3H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1M7 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2`}),`Dns`),_=e([(0,n.jsx)(`path`,{d:`M17 11h2v2h-2v2h2v2h-2v2h4V5h-9v1.4l5 3.57zm0-4h2v2h-2z`,opacity:`.3`},`0`),(0,n.jsx)(`path`,{d:`M10 3v1.97l.96.69L12 6.4V5h9v14h-4v2h6V3z`},`1`),(0,n.jsx)(`path`,{d:`M3 12v7h2v-5h6v5h2v-7L8 8.5z`,opacity:`.3`},`2`),(0,n.jsx)(`path`,{d:`M17 7h2v2h-2zm0 4h2v2h-2zm0 4h2v2h-2zM1 11v10h6v-5h2v5h6V11L8 6zm12 8h-2v-5H5v5H3v-7l5-3.5 5 3.5z`},`3`)],`HomeWorkTwoTone`),v=e((0,n.jsx)(`path`,{d:`M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2m-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2m3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1s3.1 1.39 3.1 3.1z`}),`Lock`),y=e([(0,n.jsx)(`path`,{d:`M14.99 4.59V5c0 1.1-.9 2-2 2h-2v2c0 .55-.45 1-1 1h-2v2h6c.55 0 1 .45 1 1v3h1c.89 0 1.64.59 1.9 1.4C19.19 15.98 20 14.08 20 12c0-3.35-2.08-6.23-5.01-7.41M8.99 16v-1l-4.78-4.78C4.08 10.79 4 11.39 4 12c0 4.07 3.06 7.43 6.99 7.93V18c-1.1 0-2-.9-2-2`,opacity:`.3`},`0`),(0,n.jsx)(`path`,{d:`M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m-1.01 17.93C7.06 19.43 4 16.07 4 12c0-.61.08-1.21.21-1.78L8.99 15v1c0 1.1.9 2 2 2zm6.9-2.53c-.26-.81-1-1.4-1.9-1.4h-1v-3c0-.55-.45-1-1-1h-6v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41C17.92 5.77 20 8.65 20 12c0 2.08-.81 3.98-2.11 5.4`},`1`)],`PublicTwoTone`),b=e([(0,n.jsx)(`path`,{d:`M15 15H5v4h14v-4zm-7 3H6v-2h2zm3.5 0h-2v-2h2zm3.5 0h-2v-2h2z`,opacity:`.3`},`0`),(0,n.jsx)(`path`,{d:`M16 4.2c1.5 0 3 .6 4.2 1.7l.8-.8C19.6 3.7 17.8 3 16 3s-3.6.7-5 2.1l.8.8C13 4.8 14.5 4.2 16 4.2m-3.3 2.5.8.8c.7-.7 1.6-1 2.5-1s1.8.3 2.5 1l.8-.8c-.9-.9-2.1-1.4-3.3-1.4s-2.4.5-3.3 1.4M19 13h-2V9h-2v4H5c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-4c0-1.1-.9-2-2-2m0 6H5v-4h14zM6 16h2v2H6zm3.5 0h2v2h-2zm3.5 0h2v2h-2z`},`1`)],`RouterTwoTone`),x=e((0,n.jsx)(`path`,{d:`M2.01 21 23 12 2.01 3 2 10l15 2-15 2z`}),`Send`),S=e((0,n.jsx)(`path`,{d:`M2 20h20v-4H2zm2-3h2v2H4zM2 4v4h20V4zm4 3H4V5h2zm-4 7h20v-4H2zm2-3h2v2H4z`}),`Storage`),C=e((0,n.jsx)(`path`,{d:`M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14`}),`Search`),w=e((0,n.jsx)(`path`,{d:`M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6z`}),`Add`),T=e((0,n.jsx)(`path`,{d:`m4 12 1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8z`}),`ArrowUpward`),E=e((0,n.jsx)(`path`,{d:`m20 12-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8z`}),`ArrowDownward`),D=e((0,n.jsx)(`path`,{d:`M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8`}),`Undo`),O=e((0,n.jsx)(`path`,{d:`M4.25 5.61C6.27 8.2 10 13 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-6s3.72-4.8 5.74-7.39c.51-.66.04-1.61-.79-1.61H5.04c-.83 0-1.3.95-.79 1.61`}),`FilterAlt`),k=e((0,n.jsx)(`path`,{d:`M17 7h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1 0 1.43-.98 2.63-2.31 2.98l1.46 1.46C20.88 15.61 22 13.95 22 12c0-2.76-2.24-5-5-5m-1 4h-2.19l2 2H16zM2 4.27l3.11 3.11C3.29 8.12 2 9.91 2 12c0 2.76 2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1 0-1.59 1.21-2.9 2.76-3.07L8.73 11H8v2h2.73L13 15.27V17h1.73l4.01 4L20 19.74 3.27 3z`}),`LinkOff`),A=e((0,n.jsx)(`path`,{d:`M5 13h14v-2H5zm-2 4h14v-2H3zM7 7v2h14V7z`}),`ClearAll`),ee=e((0,n.jsx)(`path`,{d:`M20 9V7c0-1.1-.9-2-2-2h-3c0-1.66-1.34-3-3-3S9 3.34 9 5H6c-1.1 0-2 .9-2 2v2c-1.66 0-3 1.34-3 3s1.34 3 3 3v4c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-4c1.66 0 3-1.34 3-3s-1.34-3-3-3M7.5 11.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5S9.83 13 9 13s-1.5-.67-1.5-1.5M16 17H8v-2h8zm-1-4c-.83 0-1.5-.67-1.5-1.5S14.17 10 15 10s1.5.67 1.5 1.5S15.83 13 15 13`}),`SmartToy`),j=e((0,n.jsx)(`path`,{d:`M20 4H4c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.89-2-2-2m0 14H4V8h16zm-2-1h-6v-2h6zM7.5 17l-1.41-1.41L8.67 13l-2.59-2.59L7.5 9l4 4z`}),`Terminal`),M=e((0,n.jsx)(`path`,{d:`M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2m0 16H8V7h11z`}),`ContentCopy`),N=e((0,n.jsx)(`path`,{d:`M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2M4 12c0-4.42 3.58-8 8-8 1.85 0 3.55.63 4.9 1.69L5.69 16.9C4.63 15.55 4 13.85 4 12m8 8c-1.85 0-3.55-.63-4.9-1.69L18.31 7.1C19.37 8.45 20 10.15 20 12c0 4.42-3.58 8-8 8`}),`Block`),P=e((0,n.jsx)(`path`,{d:`M20 6h-8l-2-2H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2m-2 6h-2v2h2v2h-2v2h-2v-2h2v-2h-2v-2h2v-2h-2V8h2v2h2z`}),`FolderZip`),F=e((0,n.jsx)(`path`,{d:`M15.41 7.41 14 6l-6 6 6 6 1.41-1.41L10.83 12z`}),`ChevronLeft`),I=e((0,n.jsx)(`path`,{d:`M3 10h11v2H3zm0-2h11V6H3zm0 8h7v-2H3zm15.01-3.13.71-.71c.39-.39 1.02-.39 1.41 0l.71.71c.39.39.39 1.02 0 1.41l-.71.71zm-.71.71-5.3 5.3V21h2.12l5.3-5.3z`}),`EditNote`),L=e((0,n.jsx)(`path`,{d:`M5 17h14v2H5zm7-12L5.33 15h13.34z`}),`Eject`),R=e((0,n.jsx)(`path`,{d:`M20 6h-8l-2-2H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2m-1 8h-3v3h-2v-3h-3v-2h3V9h2v3h3z`}),`CreateNewFolder`),z=e((0,n.jsx)(`path`,{d:`M8 11h3v10h2V11h3l-4-4zM4 3v2h16V3z`}),`VerticalAlignTop`),B=e([(0,n.jsx)(`path`,{d:`M2 16.5C2 19.54 4.46 22 7.5 22s5.5-2.46 5.5-5.5V10H2zm5.5 2C6.12 18.5 5 17.83 5 17h5c0 .83-1.12 1.5-2.5 1.5M10 13c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1m-5 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1`},`0`),(0,n.jsx)(`path`,{d:`M11 3v6h3v2.5c0-.83 1.12-1.5 2.5-1.5s2.5.67 2.5 1.5h-5v2.89c.75.38 1.6.61 2.5.61 3.04 0 5.5-2.46 5.5-5.5V3zm3 5.08c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1c0 .56-.45 1-1 1m5 0c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1c0 .56-.45 1-1 1`},`1`)],`TheaterComedy`),V=e((0,n.jsx)(`path`,{d:`M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8z`}),`Folder`),H=e((0,n.jsx)(`path`,{d:`M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1M8 13h8v-2H8zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5`}),`Link`),U=e((0,n.jsx)(`path`,{d:`M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8zM6 20V4h7v5h5v11z`}),`InsertDriveFileOutlined`),W=e((0,n.jsx)(`path`,{d:`M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5M12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5m0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3`}),`RemoveRedEye`),G=e((0,n.jsx)(`path`,{d:`M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2m-5 14H4v-4h11zm0-5H4V9h11zm5 5h-4V9h4z`}),`Web`),K=e((0,n.jsx)(`path`,{d:`M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96`}),`Cloud`),q=e((0,n.jsx)(`path`,{d:`M14.59 8 12 10.59 9.41 8 8 9.41 10.59 12 8 14.59 9.41 16 12 13.41 14.59 16 16 14.59 13.41 12 16 9.41zM12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2m0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8`}),`HighlightOff`),J=e((0,n.jsx)(`path`,{d:`M12 5.83 15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15z`}),`UnfoldMore`),Y=e((0,n.jsx)(`path`,{d:`M7.41 18.59 8.83 20 12 16.83 15.17 20l1.41-1.41L12 14zm9.18-13.18L15.17 4 12 7.17 8.83 4 7.41 5.41 12 10z`}),`UnfoldLess`),X=e((0,n.jsx)(`path`,{d:`M9.64 7.64c.23-.5.36-1.05.36-1.64 0-2.21-1.79-4-4-4S2 3.79 2 6s1.79 4 4 4c.59 0 1.14-.13 1.64-.36L10 12l-2.36 2.36C7.14 14.13 6.59 14 6 14c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4c0-.59-.13-1.14-.36-1.64L12 14l7 7h3v-1zM6 8c-1.1 0-2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2m0 12c-1.1 0-2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2m6-7.5c-.28 0-.5-.22-.5-.5s.22-.5.5-.5.5.22.5.5-.22.5-.5.5M19 3l-6 6 2 2 7-7V3z`}),`ContentCut`),Z=e((0,n.jsx)(`path`,{d:`M19 2h-4.18C14.4.84 13.3 0 12 0S9.6.84 9.18 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2m-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1m7 18H5V4h2v3h10V4h2z`}),`ContentPaste`),Q=e((0,n.jsx)(`path`,{d:`M15 21h-2v-2h2zm-2-7h-2v5h2zm8-2h-2v4h2zm-2-2h-2v2h2zM7 12H5v2h2zm-2-2H3v2h2zm7-5h2V3h-2zm-7.5-.5v3h3v-3zM9 9H3V3h6zm-4.5 7.5v3h3v-3zM9 21H3v-6h6zm7.5-16.5v3h3v-3zM21 9h-6V3h6zm-2 10v-3h-4v2h2v3h4v-2zm-2-7h-4v2h4zm-4-2H7v2h2v2h2v-2h2zm1-1V7h-2V5h-2v4zM6.75 5.25h-1.5v1.5h1.5zm0 12h-1.5v1.5h1.5zm12-12h-1.5v1.5h1.5z`}),`QrCode2`),$=e((0,n.jsx)(`path`,{d:`M18 4V3c0-.55-.45-1-1-1H5c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h12c.55 0 1-.45 1-1V6h1v4H9v11c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-9h8V4z`}),`FormatPaint`),te=e((0,n.jsx)(`path`,{d:`M19 5v14H5V5zm1.1-2H3.9c-.5 0-.9.4-.9.9v16.2c0 .4.4.9.9.9h16.2c.4 0 .9-.5.9-.9V3.9c0-.5-.5-.9-.9-.9M11 7h6v2h-6zm0 4h6v2h-6zm0 4h6v2h-6zM7 7h2v2H7zm0 4h2v2H7zm0 4h2v2H7z`}),`ListAlt`),ne=e((0,n.jsx)(`path`,{d:`M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m4 14H8V8h8z`}),`StopCircle`),re=e((0,n.jsx)(`path`,{d:`M16 18v2H8v-2zM11 7.99V16h2V7.99h3L12 4 8 7.99z`}),`Upgrade`),ie=e((0,n.jsx)(`path`,{d:`M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z`}),`Clear`),ae=e((0,n.jsx)(`path`,{d:`M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20z`}),`ArrowBack`),oe=e((0,n.jsx)(`path`,{d:`m12 4-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z`}),`ArrowForward`);export{c as $,ee as A,x as B,L as C,N as D,P as E,E as F,g as G,y as H,T as I,p as J,h as K,w as L,k as M,O as N,M as O,D as P,l as Q,C as R,R as S,F as T,v as U,b as V,_ as W,d as X,f as Y,u as Z,U as _,ne as a,B as b,Q as c,Y as d,s as et,J as f,W as g,G as h,re as i,r as it,A as j,j as k,Z as l,K as m,ae as n,a as nt,te as o,q as p,m as q,ie as r,i as rt,$ as s,oe as t,o as tt,X as u,H as v,I as w,z as x,V as y,S as z};