hfs 3.4.0-alpha1 → 3.4.0-beta3

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 (110) hide show
  1. package/admin/assets/AccountsPage-CoiPofEv.js +4 -0
  2. package/admin/assets/{ConfigFilePage-D5TZZyMR.js → ConfigFilePage-jUH2feqi.js} +1 -1
  3. package/admin/assets/{CustomHtmlPage-DV2-ufWZ.js → CustomHtmlPage-Pl_AJZrl.js} +1 -1
  4. package/admin/assets/{InternetPage-DT3wSQYQ.js → InternetPage-DIcAwhFk.js} +1 -1
  5. package/admin/assets/{LangPage-DbXCv7wR.js → LangPage-BwVY8QRD.js} +1 -1
  6. package/admin/assets/{LogsPage-DmAxUZpu.js → LogsPage-CcjS12cP.js} +1 -1
  7. package/admin/assets/{MonitorPage-D7ydOeq_.js → MonitorPage-DMVFXyMe.js} +1 -1
  8. package/admin/assets/OptionsPage-BB40ax9G.js +3 -0
  9. package/admin/assets/{PluginsPage-BYzfwuvg.js → PluginsPage-CC2dINcb.js} +1 -1
  10. package/admin/assets/{icons-CfBG9vvB.js → icons-C_ux1zLA.js} +1 -1
  11. package/admin/assets/{index-CVCnYMoB.js → index-BSSQOMG_.js} +4 -4
  12. package/admin/assets/{routing-C4l8rnk_.js → routing-Be72yFmd.js} +1 -1
  13. package/admin/index.html +1 -1
  14. package/frontend/assets/{dist-legacy-CKczq_fx.js → dist-legacy-D7Dg5w3L.js} +1 -1
  15. package/frontend/assets/index-legacy-CnazC3Dj.js +1 -0
  16. package/frontend/assets/{lib-legacy-D2tyILlj.js → lib-legacy-BxFHpdER.js} +1 -1
  17. package/frontend/assets/{sha512-legacy-CFcDeiiP.js → sha512-legacy-C8xoQBnP.js} +1 -1
  18. package/frontend/index.html +1 -1
  19. package/npm-shrinkwrap.json +66 -66
  20. package/package.json +3 -3
  21. package/plugins/antibrute/plugin.js +72 -18
  22. package/src/admin-langs/embedded.js +2 -2
  23. package/src/admin-langs/hfs-admin-lang-ar.json +34 -26
  24. package/src/admin-langs/hfs-admin-lang-bg.json +35 -27
  25. package/src/admin-langs/hfs-admin-lang-de.json +37 -29
  26. package/src/admin-langs/hfs-admin-lang-el.json +38 -30
  27. package/src/admin-langs/hfs-admin-lang-en.json +8 -0
  28. package/src/admin-langs/hfs-admin-lang-es.json +37 -29
  29. package/src/admin-langs/hfs-admin-lang-fi.json +100 -92
  30. package/src/admin-langs/hfs-admin-lang-fr.json +39 -31
  31. package/src/admin-langs/hfs-admin-lang-hu.json +37 -29
  32. package/src/admin-langs/hfs-admin-lang-it.json +35 -27
  33. package/src/admin-langs/hfs-admin-lang-ja.json +36 -28
  34. package/src/admin-langs/hfs-admin-lang-ko.json +39 -31
  35. package/src/admin-langs/hfs-admin-lang-lt.json +35 -27
  36. package/src/admin-langs/hfs-admin-lang-ms.json +36 -28
  37. package/src/admin-langs/hfs-admin-lang-nl.json +36 -28
  38. package/src/admin-langs/hfs-admin-lang-pl.json +36 -28
  39. package/src/admin-langs/hfs-admin-lang-pt-br.json +36 -28
  40. package/src/admin-langs/hfs-admin-lang-ro.json +37 -29
  41. package/src/admin-langs/hfs-admin-lang-ru.json +35 -27
  42. package/src/admin-langs/hfs-admin-lang-sr-latn.json +35 -27
  43. package/src/admin-langs/hfs-admin-lang-sr.json +39 -31
  44. package/src/admin-langs/hfs-admin-lang-th.json +35 -27
  45. package/src/admin-langs/hfs-admin-lang-tr.json +38 -30
  46. package/src/admin-langs/hfs-admin-lang-uk.json +35 -27
  47. package/src/admin-langs/hfs-admin-lang-vi.json +35 -27
  48. package/src/admin-langs/hfs-admin-lang-zh-hant.json +1149 -0
  49. package/src/admin-langs/hfs-admin-lang-zh.json +728 -720
  50. package/src/adminApis.js +2 -1
  51. package/src/adminLang.js +8 -7
  52. package/src/api.accounts.js +9 -4
  53. package/src/api.auth.js +11 -3
  54. package/src/api.log.js +1 -2
  55. package/src/api.vfs.js +3 -2
  56. package/src/auth.js +25 -14
  57. package/src/consoleLog.js +4 -0
  58. package/src/const.js +1 -1
  59. package/src/cross-const.js +1 -1
  60. package/src/cross.js +1 -1
  61. package/src/customHtml.js +3 -2
  62. package/src/deletePermission.js +120 -0
  63. package/src/events.js +6 -0
  64. package/src/index.js +3 -2
  65. package/src/lang.js +6 -1
  66. package/src/langs/embedded.js +2 -2
  67. package/src/langs/hfs-lang-ar.json +2 -1
  68. package/src/langs/hfs-lang-bg.json +2 -1
  69. package/src/langs/hfs-lang-de.json +2 -1
  70. package/src/langs/hfs-lang-el.json +2 -1
  71. package/src/langs/hfs-lang-en.json +2 -1
  72. package/src/langs/hfs-lang-es.json +2 -1
  73. package/src/langs/hfs-lang-fi.json +2 -1
  74. package/src/langs/hfs-lang-fr.json +2 -1
  75. package/src/langs/hfs-lang-hu.json +2 -1
  76. package/src/langs/hfs-lang-it.json +2 -1
  77. package/src/langs/hfs-lang-ja.json +2 -1
  78. package/src/langs/hfs-lang-ko.json +2 -1
  79. package/src/langs/hfs-lang-lt.json +2 -1
  80. package/src/langs/hfs-lang-ms.json +2 -1
  81. package/src/langs/hfs-lang-nl.json +2 -1
  82. package/src/langs/hfs-lang-pl.json +2 -1
  83. package/src/langs/hfs-lang-pt-br.json +2 -1
  84. package/src/langs/hfs-lang-ro.json +2 -1
  85. package/src/langs/hfs-lang-ru.json +2 -1
  86. package/src/langs/hfs-lang-sr-latn.json +2 -1
  87. package/src/langs/hfs-lang-sr.json +2 -1
  88. package/src/langs/hfs-lang-th.json +2 -1
  89. package/src/langs/hfs-lang-tr.json +2 -1
  90. package/src/langs/hfs-lang-uk.json +2 -1
  91. package/src/langs/hfs-lang-vi.json +2 -1
  92. package/src/langs/hfs-lang-zh-hant.json +189 -0
  93. package/src/langs/hfs-lang-zh.json +96 -98
  94. package/src/listen.js +8 -4
  95. package/src/middlewares.js +31 -28
  96. package/src/perm.js +26 -4
  97. package/src/plugins.js +2 -2
  98. package/src/serveFile.js +5 -9
  99. package/src/serveGuiAndSharedFiles.js +9 -8
  100. package/src/serveGuiFiles.js +2 -2
  101. package/src/sessionStamp.js +53 -0
  102. package/src/upload.js +1 -1
  103. package/src/uploadOwners.js +4 -2
  104. package/src/vfs.js +80 -33
  105. package/src/webdav.js +2 -2
  106. package/admin/assets/AccountsPage-C6J2hRcY.js +0 -4
  107. package/admin/assets/OptionsPage-DpN3ajRm.js +0 -3
  108. package/frontend/assets/index-legacy-ZYae30AY.js +0 -1
  109. package/src/admin-langs/hfs-admin-lang-zh-tw.json +0 -1141
  110. package/src/langs/hfs-lang-zh-tw.json +0 -187
@@ -1,6 +1,6 @@
1
- exports.version = 3.2
1
+ exports.version = 3.3
2
2
  exports.description = "Introduce increasing delays between login attempts."
3
- exports.apiRequired = 9.6 // addBlock
3
+ exports.apiRequired = 13.7 // loginAttemptFinished
4
4
 
5
5
  exports.config = {
6
6
  increment: { type: 'number', min: 1, defaultValue: 5, unit: "seconds", helperText: "How longer user must wait for each login attempt" },
@@ -20,6 +20,7 @@ const byIp = new Map()
20
20
  const byAccount = new Map()
21
21
  const laneByIp = new Map()
22
22
  const laneByAccount = new Map()
23
+ const activeAttempts = new WeakMap()
23
24
  const UNKNOWN_ACCOUNT = 'unknown\t'
24
25
 
25
26
  exports.init = api => {
@@ -29,7 +30,7 @@ exports.init = api => {
29
30
  let waitingGlobal = 0
30
31
  const QUEUE_FULL = Symbol('queue_full')
31
32
  api.events.multi({
32
- async attemptingLogin({ ctx, username }) {
33
+ async attemptingLogin({ ctx, username, via }) {
33
34
  const { ip } = ctx
34
35
  const account = getAccountKey(username)
35
36
  const ipRec = getRecord(byIp, ip)
@@ -47,16 +48,14 @@ exports.init = api => {
47
48
  waitingGlobal++
48
49
  admitted = true
49
50
  })
50
- // serialize waits per ip and per account so parallel bursts can't consume the same penalty window
51
- await runInLane(getLane(laneByIp, ip), () =>
52
- runInLane(getLane(laneByAccount, account), async () => {
53
- const now = Date.now()
54
- const wait = Math.max(0, ipRec.next - now, accountRec.next - now)
55
- if (wait <= 0) return
56
- api.log('delaying', ip, 'for', Math.round(wait / 1000))
57
- ctx.set('x-anti-brute-force', wait)
58
- await new Promise(resolve => setTimeout(resolve, wait))
59
- }))
51
+ const lanes = [getLane(laneByIp, ip), getLane(laneByAccount, account)]
52
+ if (via === 'srp')
53
+ await runInLanes(lanes, () => waitForPenalty(ctx, ipRec, accountRec))
54
+ else {
55
+ // hold the lanes through credential verification so a parallel burst observes each preceding result
56
+ await enterAttempt(ctx, lanes, { ip, account, ipRec, accountRec })
57
+ admitted = false
58
+ }
60
59
  }
61
60
  catch (e) {
62
61
  if (e === QUEUE_FULL) {
@@ -77,6 +76,15 @@ exports.init = api => {
77
76
  dropLaneIfIdle(laneByAccount, account)
78
77
  }
79
78
  },
79
+ loginAttemptFinished({ ctx, success }) {
80
+ const attempt = activeAttempts.get(ctx)
81
+ if (!attempt) return
82
+ activeAttempts.delete(ctx)
83
+ if (success)
84
+ resetRecord(byAccount, attempt.account)
85
+ finishAdmission(attempt)
86
+ attempt.release()
87
+ },
80
88
  failedLogin({ ctx, username }) {
81
89
  const { ip } = ctx
82
90
  const account = getAccountKey(username)
@@ -96,11 +104,8 @@ exports.init = api => {
96
104
  },
97
105
  login(ctx) {
98
106
  if (ctx.state.account) {
99
- const { ip } = ctx
100
107
  const account = getAccountKey(ctx.state.account.username)
101
- resetRecord(byIp, ip)
102
108
  resetRecord(byAccount, account)
103
- dropLaneIfIdle(laneByIp, ip)
104
109
  dropLaneIfIdle(laneByAccount, account)
105
110
  }
106
111
  }
@@ -109,9 +114,14 @@ exports.init = api => {
109
114
  function getRecord(container, key) {
110
115
  let rec = container.get(key)
111
116
  if (!rec) {
112
- rec = { failures: 0, next: 0, waiting: 0 }
117
+ rec = { failures: 0, next: 0, expires: 0, waiting: 0 }
113
118
  container.set(key, rec)
114
119
  }
120
+ // successful attempts may keep the record alive, but must not extend its penalties
121
+ if (rec.expires <= Date.now()) {
122
+ rec.failures = 0
123
+ rec.next = 0
124
+ }
115
125
  return rec
116
126
  }
117
127
 
@@ -120,6 +130,7 @@ exports.init = api => {
120
130
  const max = api.getConfig('max') * 1000
121
131
  const delay = Math.min(max, attempts * api.getConfig('increment') * 1000)
122
132
  rec.next = Math.max(now, rec.next) + delay
133
+ rec.expires = now + 24 * HOUR
123
134
  return attempts
124
135
  }
125
136
 
@@ -130,7 +141,7 @@ exports.init = api => {
130
141
  if (rec.waiting)
131
142
  return armCleanup(records, key, rec)
132
143
  records.delete(key)
133
- }, 24 * HOUR) // no memory leak
144
+ }, 24 * HOUR) // idle memory cleanup, independent of penalty expiry
134
145
  }
135
146
 
136
147
  function runGate(job) {
@@ -160,6 +171,47 @@ exports.init = api => {
160
171
  })
161
172
  }
162
173
 
174
+ function runInLanes([lane, ...rest], job) {
175
+ return lane ? runInLane(lane, () => runInLanes(rest, job)) : job()
176
+ }
177
+
178
+ function enterAttempt(ctx, lanes, attempt) {
179
+ return new Promise((resolve, reject) => {
180
+ let release
181
+ const held = runInLanes(lanes, async () => {
182
+ await waitForPenalty(ctx, attempt.ipRec, attempt.accountRec)
183
+ await new Promise(done => {
184
+ release = done
185
+ activeAttempts.set(ctx, { ...attempt, release })
186
+ resolve()
187
+ })
188
+ })
189
+ held.catch(reject).finally(() => {
190
+ dropLaneIfIdle(laneByIp, attempt.ip)
191
+ dropLaneIfIdle(laneByAccount, attempt.account)
192
+ })
193
+ })
194
+ }
195
+
196
+ async function waitForPenalty(ctx, ipRec, accountRec) {
197
+ const now = Date.now()
198
+ // accumulated delays must not outlive the failures that caused them
199
+ const wait = Math.max(0, Math.min(ipRec.next, ipRec.expires) - now,
200
+ Math.min(accountRec.next, accountRec.expires) - now)
201
+ if (wait <= 0) return
202
+ api.log('delaying', ctx.ip, 'for', Math.round(wait / 1000))
203
+ ctx.set('x-anti-brute-force', wait)
204
+ await new Promise(resolve => setTimeout(resolve, wait))
205
+ }
206
+
207
+ function finishAdmission({ ip, account, ipRec, accountRec }) {
208
+ ipRec.waiting--
209
+ accountRec.waiting--
210
+ waitingGlobal--
211
+ armCleanup(byIp, ip, ipRec)
212
+ armCleanup(byAccount, account, accountRec)
213
+ }
214
+
163
215
  function dropLaneIfIdle(container, key) {
164
216
  const q = container.get(key)
165
217
  if (q?.isWorking() || q?.queueSize()) return
@@ -173,8 +225,10 @@ exports.init = api => {
173
225
  // successful login must clear penalties without dropping admission counters still needed by concurrent requests
174
226
  rec.failures = 0
175
227
  rec.next = 0
228
+ rec.expires = 0
176
229
  return
177
230
  }
231
+ clearTimeout(rec.timer) // an old timer must not delete a replacement record for the same account
178
232
  container.delete(key)
179
233
  }
180
234
 
@@ -12,7 +12,7 @@ const hfs_admin_lang_sr_json_1 = __importDefault(require("./hfs-admin-lang-sr.js
12
12
  const hfs_admin_lang_sr_latn_json_1 = __importDefault(require("./hfs-admin-lang-sr-latn.json"));
13
13
  const hfs_admin_lang_ko_json_1 = __importDefault(require("./hfs-admin-lang-ko.json"));
14
14
  const hfs_admin_lang_ms_json_1 = __importDefault(require("./hfs-admin-lang-ms.json"));
15
- const hfs_admin_lang_zh_tw_json_1 = __importDefault(require("./hfs-admin-lang-zh-tw.json"));
15
+ const hfs_admin_lang_zh_hant_json_1 = __importDefault(require("./hfs-admin-lang-zh-hant.json"));
16
16
  const hfs_admin_lang_fr_json_1 = __importDefault(require("./hfs-admin-lang-fr.json"));
17
17
  const hfs_admin_lang_pl_json_1 = __importDefault(require("./hfs-admin-lang-pl.json"));
18
18
  const hfs_admin_lang_pt_br_json_1 = __importDefault(require("./hfs-admin-lang-pt-br.json"));
@@ -30,4 +30,4 @@ const hfs_admin_lang_uk_json_1 = __importDefault(require("./hfs-admin-lang-uk.js
30
30
  const hfs_admin_lang_ar_json_1 = __importDefault(require("./hfs-admin-lang-ar.json"));
31
31
  const hfs_admin_lang_lt_json_1 = __importDefault(require("./hfs-admin-lang-lt.json"));
32
32
  const hfs_admin_lang_bg_json_1 = __importDefault(require("./hfs-admin-lang-bg.json"));
33
- exports.default = { en: hfs_admin_lang_en_json_1.default, it: hfs_admin_lang_it_json_1.default, zh: hfs_admin_lang_zh_json_1.default, ru: hfs_admin_lang_ru_json_1.default, ro: hfs_admin_lang_ro_json_1.default, sr: hfs_admin_lang_sr_json_1.default, 'sr-latn': hfs_admin_lang_sr_latn_json_1.default, ko: hfs_admin_lang_ko_json_1.default, ms: hfs_admin_lang_ms_json_1.default, 'zh-tw': hfs_admin_lang_zh_tw_json_1.default, fr: hfs_admin_lang_fr_json_1.default, pl: hfs_admin_lang_pl_json_1.default, 'pt-br': hfs_admin_lang_pt_br_json_1.default, vi: hfs_admin_lang_vi_json_1.default, es: hfs_admin_lang_es_json_1.default, nl: hfs_admin_lang_nl_json_1.default, el: hfs_admin_lang_el_json_1.default, de: hfs_admin_lang_de_json_1.default, fi: hfs_admin_lang_fi_json_1.default, hu: hfs_admin_lang_hu_json_1.default, ja: hfs_admin_lang_ja_json_1.default, tr: hfs_admin_lang_tr_json_1.default, th: hfs_admin_lang_th_json_1.default, uk: hfs_admin_lang_uk_json_1.default, ar: hfs_admin_lang_ar_json_1.default, lt: hfs_admin_lang_lt_json_1.default, bg: hfs_admin_lang_bg_json_1.default };
33
+ exports.default = { en: hfs_admin_lang_en_json_1.default, it: hfs_admin_lang_it_json_1.default, zh: hfs_admin_lang_zh_json_1.default, ru: hfs_admin_lang_ru_json_1.default, ro: hfs_admin_lang_ro_json_1.default, sr: hfs_admin_lang_sr_json_1.default, 'sr-latn': hfs_admin_lang_sr_latn_json_1.default, ko: hfs_admin_lang_ko_json_1.default, ms: hfs_admin_lang_ms_json_1.default, 'zh-hant': hfs_admin_lang_zh_hant_json_1.default, fr: hfs_admin_lang_fr_json_1.default, pl: hfs_admin_lang_pl_json_1.default, 'pt-br': hfs_admin_lang_pt_br_json_1.default, vi: hfs_admin_lang_vi_json_1.default, es: hfs_admin_lang_es_json_1.default, nl: hfs_admin_lang_nl_json_1.default, el: hfs_admin_lang_el_json_1.default, de: hfs_admin_lang_de_json_1.default, fi: hfs_admin_lang_fi_json_1.default, hu: hfs_admin_lang_hu_json_1.default, ja: hfs_admin_lang_ja_json_1.default, tr: hfs_admin_lang_tr_json_1.default, th: hfs_admin_lang_th_json_1.default, uk: hfs_admin_lang_uk_json_1.default, ar: hfs_admin_lang_ar_json_1.default, lt: hfs_admin_lang_lt_json_1.default, bg: hfs_admin_lang_bg_json_1.default };
@@ -2,6 +2,10 @@
2
2
  "author": "Automatic translation",
3
3
  "version": 1,
4
4
  "translate": {
5
+ "Using a hostname?": "هل تستخدم اسم مضيف؟",
6
+ "Configure it first": "قم بتكوينه أولاً",
7
+ "auto_login_net_help": "تعمل عناوين IP وlocalhost دون إعداد إضافي.\nإذا كنت تصل إلى HFS باستخدام اسم مضيف، فقم بتكوينه ضمن الإنترنت ← العنوان كعنوان رئيسي أو في جذور النطاقات، وأدرج المنفذ إذا ظهر في العنوان.\nيمنع ذلك موقعًا ضارًا من استخدام عنوان IP المصرح به للمتصفح لتسجيل الدخول عبر إعادة ربط DNS. كوّن النطاقات الموثوقة فقط وتجنب أحرف البدل الواسعة جدًا.\nبالنسبة لأسماء المضيف الأخرى، يتم تخطي الدخول التلقائي، لكن يظل الدخول ببيانات الاعتماد متاحًا.",
8
+ "Configure your firewall to allow only trusted proxies to connect to HFS.": "اضبط جدار الحماية للسماح للوكلاء الموثوقين فقط بالاتصال بـ HFS.",
5
9
  "Include hidden files": "تضمين الملفات المخفية",
6
10
  "Case-insensitive": "لا يميز بين الأحرف الكبيرة والصغيرة",
7
11
  "non_public_ip_warning": "هذا عنوان IP غير عام. لا يمكن الوصول إليه مباشرة من الإنترنت. استخدم عنوان IP عامًا أو اسم نطاق بدلًا منه.",
@@ -36,7 +40,7 @@
36
40
  "Frontend": "واجهة المستخدم",
37
41
  "Admin": "الإدارة",
38
42
  "Net": "الشبكة",
39
- "Front-end": "الواجهة الأمامية",
43
+ "Front-end": "واجهة المستخدم",
40
44
  "Uploads": "التحميلات",
41
45
  "Others": "أخرى",
42
46
  "(already invalidated sessions before {timestamp})": "(تم إبطال الجلسات من قبل {timestamp})",
@@ -68,7 +72,7 @@
68
72
  "log_partial_upload": "تحميل جزئي",
69
73
  "log_partial_upload_at_speed": "تحميل جزئي {speed}",
70
74
  "unknown_value": "*غير معروف*{value}",
71
- "✅ {value}\n 🚫 {failed}": "✅ {value} 🚫 {failed}",
75
+ "✅ {value}\n 🚫 {failed}": "✅ {value}\n 🚫 {failed}",
72
76
  "$1removed@": "تمت إزالة $1@",
73
77
  "router_bug_reboot_hint": "هناك خطأ في المودم/جهاز التوجيه الخاص بك، حاول إعادة تشغيله.",
74
78
  "A plugin has the same power of any other software": "يتمتع البرنامج الإضافي بنفس قوة أي برنامج آخر",
@@ -98,9 +102,9 @@
98
102
  "Admin-panel access": "الوصول إلى لوحة الإدارة",
99
103
  "Admin-panel accessible from": "يمكن الوصول إلى لوحة الإدارة من",
100
104
  "Admin-panel only for localhost": "لوحة الإدارة للمضيف المحلي فقط",
101
- "agent": "عامل",
102
- "Agent": "عامل",
103
- "Agent text": "نص الوكيل",
105
+ "agent": "العميل",
106
+ "Agent": "العميل",
107
+ "Agent text": "User-Agent",
104
108
  "all .5s": "كل .5 ثانية",
105
109
  "all {timeout}ms": "جميع {timeout}ms",
106
110
  "All plugins are paused – Click the Resume button below": "تم إيقاف جميع المكونات الإضافية مؤقتًا - انقر فوق الزر \"استئناف\" أدناه",
@@ -129,7 +133,7 @@
129
133
  "API {name}{params}": "واجهة برمجة التطبيقات {name}{params}",
130
134
  "apply": "يتقدم",
131
135
  "Apply": "يتقدم",
132
- "Apply\n(ctrl+s)": "تطبيق (ctrl+s)",
136
+ "Apply\n(ctrl+s)": "تطبيق\n(ctrl+s)",
133
137
  "Are you sure?": "هل أنت متأكد؟",
134
138
  "same_as_permission": "كـ \"يمكن {permission}\"",
135
139
  "as parent folder": "كمجلد أصل",
@@ -152,7 +156,7 @@
152
156
  "Be careful, you can easily break things here": "كن حذرًا، يمكنك بسهولة كسر الأشياء هنا",
153
157
  "because no admin account was configured": "لأنه لم يتم تكوين حساب المسؤول",
154
158
  "belongs": "ينتمي",
155
- "birthtime": "وقت الميلاد",
159
+ "birthtime": "وقت الإنشاء",
156
160
  "block": "حاجز",
157
161
  "Block address {ip}": "حظر العنوان {ip}",
158
162
  "Block IP": "حظر IP",
@@ -160,7 +164,7 @@
160
164
  "Blocked IP": "IP المحظور",
161
165
  "bold": "عريض",
162
166
  "bottom_html_body": "الجزء السفلي من نص HTML",
163
- "BREAKPOINT": "نقطة التوقف",
167
+ "BREAKPOINT": "BREAKPOINT",
164
168
  "Browse files...": "تصفح الملفات...",
165
169
  "Browser is automatically launched with HFS": "يتم تشغيل المتصفح تلقائيًا باستخدام HFS",
166
170
  "browsing": "التصفح",
@@ -225,7 +229,7 @@
225
229
  "Console": "وحدة التحكم",
226
230
  "user_agent_log_size_warning": "يحتوي على المتصفح وربما معلومات نظام التشغيل.يمكن مضاعفة حجم السجلات الخاصة بك على القرص.",
227
231
  "Content": "محتوى",
228
- "Content-Range": "نطاق المحتوى",
232
+ "Content-Range": "Content-Range",
229
233
  "contents": "محتويات",
230
234
  "Continue": "يكمل",
231
235
  "Continue anyway": "استمر على أي حال",
@@ -380,7 +384,7 @@
380
384
  "Folder": "مجلد",
381
385
  "folder content": "محتوى المجلد",
382
386
  "port_forward_intro": "لكي يعمل نظام HFS عبر الإنترنت، تحتاج إلى وجود منفذ على المودم/جهاز التوجيه الخاص بك يتم توجيهه إلى منفذ هذا الكمبيوتر {localPort}.",
383
- "port_forward_request_help": "سيطلب هذا من جهاز التوجيه إعادة توجيه المنفذ.يمكنك استخدام نفس رقم منفذ الشبكة المحلية ({localPort})، أو منفذ مختلف.",
387
+ "port_forward_request_help": "سيطلب هذا من جهاز التوجيه إعادة توجيه المنفذ.\nيمكنك استخدام نفس رقم منفذ الشبكة المحلية ({localPort})، أو منفذ مختلف.",
384
388
  "Forbidden: the server understands the request but refuses to authorize it": "محظور: يفهم الخادم الطلب ولكنه يرفض السماح به",
385
389
  "Force HTTPS": "فرض HTTPS",
386
390
  "Force language: {x}": "لغة القوة: {x}",
@@ -393,8 +397,8 @@
393
397
  "From log": "من السجل",
394
398
  "from masks": "من الأقنعة",
395
399
  "From monitoring": "من الرصد",
396
- "frontend": "الواجهة الأمامية",
397
- "Frontend language": "لغة الواجهة",
400
+ "frontend": "واجهة المستخدم",
401
+ "Frontend language": "لغة واجهة المستخدم",
398
402
  "Frontend unreachable: ": "الواجهة الأمامية غير قابلة للوصول: ",
399
403
  "frp_tcp_warning": "تم الكشف عن FRP.لا ينبغي استخدامه مع \"type = tcp\" مع HFS.الحلول الممكنة هي",
400
404
  "log_full_download": "التنزيل الكامل",
@@ -441,7 +445,7 @@
441
445
  "https": "https",
442
446
  "HTTPS": "HTTPS",
443
447
  "HTTPS certificate file": "ملف شهادة HTTPS",
444
- "https_disabled_notice": "HTTPS معطل حاليًا.التكوين الكامل متاح في صفحة الخيارات.",
448
+ "https_disabled_notice": "HTTPS معطل حاليًا.\nالتكوين الكامل متاح في صفحة الخيارات.",
445
449
  "HTTPS needs a certificate to work.": "يحتاج HTTPS إلى شهادة للعمل.",
446
450
  "HTTPS port": "منفذ HTTPS",
447
451
  "HTTPS private key file": "HTTPS ملف المفتاح الخاص",
@@ -515,8 +519,8 @@
515
519
  "Level": "مستوى",
516
520
  "license": "رخصة",
517
521
  "Light theme": "موضوع خفيف",
518
- "Limit output": "الحد من الإخراج",
519
- "Limit output per-IP": "الحد من الإخراج لكل IP",
522
+ "Limit output": "الحد من حركة المرور الصادرة",
523
+ "Limit output per-IP": "الحد من حركة المرور الصادرة لكل IP",
520
524
  "Link": "وصلة",
521
525
  "Link created": "تم إنشاء الرابط",
522
526
  "Links from other websites": "روابط من مواقع أخرى",
@@ -734,7 +738,7 @@
734
738
  "Proxy Authentication Required: proxy authentication is required to access the resource": "مصادقة الوكيل مطلوبة: مصادقة الوكيل مطلوبة للوصول إلى المورد",
735
739
  "configured_proxies_not_detected": "تم تعيين عدد الوكلاء على {proxyCount} ولكن لم يتم اكتشاف أي منهم مؤخرًا.فكر في ضبطه على الصفر",
736
740
  "Proxy-warning": "تحذير الوكيل",
737
- "PUT": "يضع",
741
+ "PUT": "PUT",
738
742
  "QR Code": "رمز الاستجابة السريعة",
739
743
  "quit": "يترك",
740
744
  "Quit HFS": "قم بإنهاء HFS",
@@ -752,6 +756,8 @@
752
756
  "dynamic_dns_url_help": "ارجع إلى مزود خدمة DNS الخاص بك لمعرفة عنوان URL الذي يمكنه تحديث نطاقك تلقائيًا. الرموز المدعومة هي $IP4، $IP6، $IPX. اختياريًا، يمكنك إلحاق \">\" متبوعًا بتعبير عادي لتحديد الإجابة الناجحة، وإلا سيتم استخدام رمز الحالة.",
753
757
  "Reinstall previous version": "إعادة تثبيت الإصدار السابق",
754
758
  "Reject uploads that don't comply": "رفض التحميلات التي لا تلتزم",
759
+ "Require approval for uploaded HTML/SVG": "طلب موافقة المسؤول على ملفات HTML/SVG المرفوعة",
760
+ "Prevents running scripts on your website": "يمنع تشغيل النصوص البرمجية على موقعك",
755
761
  "release": "يطلق",
756
762
  "Reload": "إعادة تحميل",
757
763
  "Remove": "يزيل",
@@ -792,10 +798,10 @@
792
798
  "Rule": "قاعدة",
793
799
  "save": "يحفظ",
794
800
  "Save": "يحفظ",
795
- "Save\n(ctrl+enter)": "حفظ (ctrl+enter)",
796
- "Save\n(ctrl+s)": "حفظ (ctrl+s)",
801
+ "Save\n(ctrl+enter)": "حفظ\n(ctrl+enter)",
802
+ "Save\n(ctrl+s)": "حفظ\n(ctrl+s)",
797
803
  "Save and close": "حفظ وإغلاق",
798
- "Search": "يبحث",
804
+ "Search": "بحث",
799
805
  "Search text": "بحث في النص",
800
806
  "seconds": "ثواني",
801
807
  "Seconds": "ثواني",
@@ -850,7 +856,9 @@
850
856
  "Show log": "عرض السجل",
851
857
  "Show more": "عرض المزيد",
852
858
  "Show tree": "عرض الشجرة",
853
- "Show uploader to": "إظهار القائم بالتحميل إلى",
859
+ "Show uploader to": "من يمكنه رؤية اسم رافع الملف",
860
+ "Treat as interface asset": "التعامل كأصل للواجهة",
861
+ "Excluded from download limits; logged only when interface logging is enabled": "مستثنى من حدود التنزيل؛ يُسجل فقط عند تمكين تسجيل الواجهة",
854
862
  "Show without probing disk source": "إظهار دون التحقق من مصدر القرص",
855
863
  "since_timestamp": "منذ: {timestamp}",
856
864
  "size": "مقاس",
@@ -916,7 +924,7 @@
916
924
  "dynamic_dns_intro": "يمكن لهذه الأداة أن تبقي نطاقك محدثًا بأحدث عنوان IP الخاص بك. ليست كل الخدمات متوافقة، ومعظمها لديه برنامج خاص به لهذه المهمة، وهو أمر متفوق، ولكننا نقدم هذا الحل خفيف الوزن إذا كنت تفضل ذلك.",
917
925
  "This version is older than the one you installed. It is possible that the author found a problem with your version and decided to retire it.": "هذا الإصدار أقدم من الإصدار الذي قمت بتثبيته.من الممكن أن المؤلف وجد مشكلة في نسختك وقرر إيقافه.",
918
926
  "also_install_plugins": "سيؤدي هذا أيضًا إلى تثبيت: {plugins}",
919
- "This will ask the router to forward a port.\nYou can use the same number as the local network port ({port}), or a different one.": "سيطلب هذا من جهاز التوجيه إعادة توجيه المنفذ.يمكنك استخدام نفس رقم منفذ الشبكة المحلية ({port})، أو منفذ مختلف.",
927
+ "This will ask the router to forward a port.\nYou can use the same number as the local network port ({port}), or a different one.": "سيطلب هذا من جهاز التوجيه إعادة توجيه المنفذ.\nيمكنك استخدام نفس رقم منفذ الشبكة المحلية ({port})، أو منفذ مختلف.",
920
928
  "Those who can delete can also rename and cut/move": "أولئك الذين يمكنهم الحذف يمكنهم أيضًا إعادة التسمية والقص/النقل",
921
929
  "Tiles": "البلاط",
922
930
  "Timestamp": "الطابع الزمني",
@@ -1004,7 +1012,7 @@
1004
1012
  "warning": "تحذير",
1005
1013
  "wave .18s 5 alternate ease-in-out": "موجة .18s 5 بديلة لسهولة الدخول والخروج",
1006
1014
  "windows_file_manager_command_notice": "سنقوم بإضافة أمر بالنقر بزر الماوس الأيمن على Windows File Manager.",
1007
- "upnp_not_available_help": "لا يمكننا مساعدتك في تكوين جهاز التوجيه الخاص بك لأن UPnP غير متوفر.يمكنك العثور على مزيد من المساعدة [على موقع الويب هذا]({helpUrl}).",
1015
+ "upnp_not_available_help": "لا يمكننا مساعدتك في تكوين جهاز التوجيه الخاص بك لأن UPnP غير متوفر.\nيمكنك العثور على مزيد من المساعدة [على موقع الويب هذا]({helpUrl}).",
1008
1016
  "We suggest you to ": "نقترح عليك ذلك ",
1009
1017
  "web-link": "رابط الويب",
1010
1018
  "Web-link": "رابط الويب",
@@ -1043,7 +1051,7 @@
1043
1051
  "vfs_custom_name_hint": "يمكنك تحديد اسم مختلف عن الاسم الموجود على القرص لديك",
1044
1052
  "domain_roots_help": "يمكنك تحديد مجلدات رئيسية مختلفة (في VFS) لنطاقات مختلفة، تمامًا مثل المضيفين الظاهريين. إذا لم تتم مطابقة أي شيء، فسيتم استخدام المنزل الافتراضي.",
1045
1053
  "You can see this in the tab of your browser": "يمكنك رؤية ذلك في علامة تبويب المتصفح الخاص بك",
1046
- "custom_base_url_warning": "يمكنك كتابة أي عنوان ولكن *أنت* مسؤول عن تشغيل العنوان. تهدف هذه الوظيفة فقط إلى مساعدتك في نسخ الرابط في حالة وجود مجال أو تكوين شبكة معقد.",
1054
+ "custom_base_url_warning": "يمكنك كتابة أي عنوان ولكن *أنت* مسؤول عن تشغيل العنوان.\nتهدف هذه الوظيفة فقط إلى مساعدتك في نسخ الرابط في حالة وجود مجال أو تكوين شبكة معقد.",
1047
1055
  "current_account_delete_warning": "لا يمكنك طلب حذف الحساب الذي تستخدمه. أكمل مع الباقي؟",
1048
1056
  "change_both_ports_warning": "لا يمكنك تغيير منفذ http و https في وقت واحد.من فضلك، افعل واحدًا، ثم احفظ، ثم افعل الآخر.",
1049
1057
  "cannot_randomize_only_fixed_port": "لا يمكنك ترتيب هذا المنفذ بشكل عشوائي إلا إذا كان لديك منفذ ثابت يعمل لـ {otherProtocol}",
@@ -1055,12 +1063,12 @@
1055
1063
  "port_forward_check_existing": "قد ترغب في التحقق مما إذا كان هذا هو الحال بالفعل قبل تجربة ما يلي.",
1056
1064
  "localhost_admin_access_notice": "أنت تصل إلى لوحة الإدارة بدون حساب لأنك على مضيف محلي",
1057
1065
  "Your certificate is still good": "شهادتك لا تزال جيدة",
1058
- "configured_address_failed_testing_ip": "يبدو أن عنوانك الذي تم تكوينه {checkUrl} لا يعمل 😰 وما زلنا سنقوم باختبار عنوان IP الخاص بك 🤞",
1066
+ "configured_address_failed_testing_ip": "يبدو أن عنوانك الذي تم تكوينه {checkUrl} لا يعمل 😰\nوما زلنا سنقوم باختبار عنوان IP الخاص بك 🤞",
1059
1067
  "isp_may_block_low_ports": "ربما يقوم مزود الإنترنت الخاص بك بحظر المنافذ تحت 1024.",
1060
1068
  "internet_test_no_public_ip_cause": "لا يجوز لمزود خدمة الإنترنت الخاص بك أن يعين لك عنوان IP عامًا. ",
1061
1069
  "Your router may need to be configured. ": "قد يحتاج جهاز التوجيه الخاص بك إلى التهيئة. ",
1062
1070
  "server_reachable_over_internet": "الخادم الخاص بك يستجيب بشكل صحيح عبر الإنترنت:",
1063
- "server_reachable_only_by_ip": "يستجيب الخادم الخاص بك عبر الإنترنت 👍 ولكن ليس بالعنوان الذي تم تكوينه {checkUrl} 👎 فقط على عنوان IP الخاص بك:",
1071
+ "server_reachable_only_by_ip": "يستجيب الخادم الخاص بك عبر الإنترنت 👍\nولكن ليس بالعنوان الذي تم تكوينه {checkUrl} 👎\nفقط على عنوان IP الخاص بك:",
1064
1072
  "Your shared files can be browsed from ": "يمكن تصفح ملفاتك المشتركة من ",
1065
1073
  "installed_version_value": "لك {version}",
1066
1074
  "permission_zip": "إنشاء ZIP",
@@ -1131,7 +1139,7 @@
1131
1139
  "A group can inherit from another group.": "يمكن لمجموعة أن ترث من مجموعة أخرى.",
1132
1140
  "Listen interface": "واجهة الاستماع",
1133
1141
  "Max downloads": "الحد الأقصى للتنزيلات",
1134
- "Outbound interface": "واجهة الإرسال",
1142
+ "Outbound interface": "واجهة الشبكة الصادرة",
1135
1143
  "Outbound proxy": "وكيل الإرسال",
1136
1144
  "Get more": "أضف",
1137
1145
  "Check updates": "التحديثات",