@electerm/electerm-react 1.100.46 → 1.100.50

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.
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Common utilities for handling file drops
3
+ */
4
+
5
+ import { getFolderFromFilePath } from '../components/sftp/file-read'
6
+ import { typeMap } from './constants'
7
+
8
+ /**
9
+ * Safely get file path from dropped file
10
+ * @param {File} file - File object from drop event
11
+ * @returns {string} - File path
12
+ */
13
+ export const getFilePath = (file) => {
14
+ if (file.path) {
15
+ return file.path
16
+ }
17
+ // Try the official Electron 32+ method first if available
18
+ if (window.api && window.api.getPathForFile) {
19
+ return window.api.getPathForFile(file)
20
+ }
21
+ return file.name
22
+ }
23
+
24
+ /**
25
+ * Process dropped files and return file list
26
+ * @param {DataTransfer} dataTransfer - DataTransfer object from drop event
27
+ * @returns {Array} - Array of file objects
28
+ */
29
+ export const getDropFileList = (dataTransfer) => {
30
+ const fromFile = dataTransfer.getData('fromFile')
31
+ if (fromFile) {
32
+ return [JSON.parse(fromFile)]
33
+ }
34
+
35
+ const { files } = dataTransfer
36
+ const res = []
37
+ for (let i = 0, len = files.length; i < len; i++) {
38
+ const item = files[i]
39
+ if (!item) {
40
+ continue
41
+ }
42
+
43
+ const filePath = getFilePath(item)
44
+ const isRemote = false
45
+ const fileObj = getFolderFromFilePath(filePath, isRemote)
46
+ res.push({
47
+ ...fileObj,
48
+ type: typeMap.local
49
+ })
50
+ }
51
+ return res
52
+ }
53
+
54
+ /**
55
+ * Check if filename contains unsafe characters
56
+ * @param {string} filename - Filename to check
57
+ * @returns {boolean} - True if unsafe
58
+ */
59
+ export const isUnsafeFilename = (filename) => {
60
+ return /["'\n\r]/.test(filename)
61
+ }
@@ -27,8 +27,8 @@ const defaultRoles = [
27
27
  ]
28
28
 
29
29
  const proxyOptions = [
30
- { value: 'socks5://localhost:1080' },
31
- { value: 'http://localhost:8080' },
30
+ { value: 'socks5://127.0.0.1:1080' },
31
+ { value: 'http://127.0.0.1:8080' },
32
32
  { value: 'https://proxy.example.com:3128' }
33
33
  ]
34
34
 
@@ -180,7 +180,7 @@ export default function AIConfigForm ({ initialValues, onSubmit, showAIConfig })
180
180
  <Form.Item
181
181
  label={e('proxy')}
182
182
  name='proxyAI'
183
- tooltip='Proxy for AI API requests (e.g., socks5://localhost:1080)'
183
+ tooltip='Proxy for AI API requests (e.g., socks5://127.0.0.1:1080)'
184
184
  >
185
185
  <AutoComplete
186
186
  options={proxyOptions}
@@ -25,7 +25,7 @@ export default function renderProxy (props) {
25
25
  value: d
26
26
  }
27
27
  }),
28
- placeholder: 'socks5://localhost:1080',
28
+ placeholder: 'socks5://127.0.0.1:1080',
29
29
  allowClear: true
30
30
  }
31
31
  return (
@@ -29,9 +29,9 @@ export default function renderSshTunnels (props) {
29
29
  const [initialValues] = useState({
30
30
  sshTunnel: 'forwardRemoteToLocal',
31
31
  sshTunnelLocalPort: 12200,
32
- sshTunnelLocalHost: 'localhost',
32
+ sshTunnelLocalHost: '127.0.0.1',
33
33
  sshTunnelRemotePort: 12300,
34
- sshTunnelRemoteHost: 'localhost'
34
+ sshTunnelRemoteHost: '127.0.0.1'
35
35
  })
36
36
  const [isDynamic, setter] = useState(formData.sshTunnel === 'dynamicForward')
37
37
  const [list, setList] = useState(formData.sshTunnels || [])
@@ -85,9 +85,9 @@ export default function renderSshTunnels (props) {
85
85
  // sshTunnel is forwardRemoteToLocal or forwardLocalToRemote or dynamicForward
86
86
  const {
87
87
  sshTunnel,
88
- sshTunnelRemoteHost = 'localhost',
88
+ sshTunnelRemoteHost = '127.0.0.1',
89
89
  sshTunnelRemotePort = '',
90
- sshTunnelLocalHost = 'localhost',
90
+ sshTunnelLocalHost = '127.0.0.1',
91
91
  sshTunnelLocalPort = '',
92
92
  name
93
93
  } = item
@@ -434,7 +434,7 @@ export default class SettingCommon extends Component {
434
434
  />
435
435
  </div>
436
436
  {
437
- this.renderText('proxy', 'socks5://localhost:1080')
437
+ this.renderText('proxy', 'socks5://127.0.0.1:1080')
438
438
  }
439
439
  </div>
440
440
  )
@@ -30,6 +30,7 @@ import findParent from '../../common/find-parent'
30
30
  import sorter from '../../common/index-sorter'
31
31
  import { getFolderFromFilePath, getLocalFileInfo } from './file-read'
32
32
  import { readClipboard, copy as copyToClipboard, hasFileInClipboardText } from '../../common/clipboard'
33
+ import { getDropFileList } from '../../common/file-drop-utils'
33
34
  import fs from '../../common/fs'
34
35
  import time from '../../common/time'
35
36
  import { filesize } from 'filesize'
@@ -228,26 +229,7 @@ export default class FileSection extends React.Component {
228
229
  }
229
230
 
230
231
  getDropFileList = data => {
231
- const fromFile = data.getData('fromFile')
232
- if (fromFile) {
233
- return [JSON.parse(fromFile)]
234
- }
235
- const { files } = data
236
- const res = []
237
- for (let i = 0, len = files.length; i < len; i++) {
238
- const item = files[i]
239
- if (!item) {
240
- continue
241
- }
242
- // let file = item.getAsFile()
243
- const isRemote = false
244
- const fileObj = getFolderFromFilePath(item.path, isRemote)
245
- res.push({
246
- ...fileObj,
247
- type: typeMap.local
248
- })
249
- }
250
- return res
232
+ return getDropFileList(data)
251
233
  }
252
234
 
253
235
  onDrop = async e => {
@@ -261,6 +243,7 @@ export default class FileSection extends React.Component {
261
243
  if (!fromFiles) {
262
244
  return
263
245
  }
246
+
264
247
  while (!target.className.includes(fileItemCls)) {
265
248
  target = target.parentNode
266
249
  }
@@ -350,10 +350,10 @@ class Tab extends Component {
350
350
  const list = sshTunnelResults.map(({ sshTunnel: obj, error }, i) => {
351
351
  const {
352
352
  sshTunnelLocalPort,
353
- sshTunnelRemoteHost = 'localhost',
353
+ sshTunnelRemoteHost = '127.0.0.1',
354
354
  sshTunnelRemotePort,
355
355
  sshTunnel,
356
- sshTunnelLocalHost = 'localhost',
356
+ sshTunnelLocalHost = '127.0.0.1',
357
357
  name
358
358
  } = obj
359
359
  let tunnel
@@ -47,6 +47,7 @@ import { createTerm, resizeTerm } from './terminal-apis.js'
47
47
  import { shortcutExtend, shortcutDescExtend } from '../shortcuts/shortcut-handler.js'
48
48
  import { KeywordHighlighterAddon } from './highlight-addon.js'
49
49
  import { getLocalFileInfo } from '../sftp/file-read.js'
50
+ import { getFilePath, isUnsafeFilename } from '../../common/file-drop-utils.js'
50
51
  import { CommandTrackerAddon } from './command-tracker-addon.js'
51
52
  import AIIcon from '../icons/ai-icon.jsx'
52
53
  import { formatBytes } from '../../common/byte-format.js'
@@ -356,12 +357,8 @@ class Term extends Component {
356
357
  this.term.focus()
357
358
  }
358
359
 
359
- isUnsafeFilename = (filename) => {
360
- return /["'\n\r]/.test(filename)
361
- }
362
-
363
360
  cd = (p) => {
364
- if (this.isUnsafeFilename(p)) {
361
+ if (isUnsafeFilename(p)) {
365
362
  return message.error('File name contains unsafe characters')
366
363
  }
367
364
  this.runQuickCommand(`cd "${p}"`)
@@ -377,7 +374,7 @@ class Term extends Component {
377
374
  try {
378
375
  const fileData = JSON.parse(fromFile)
379
376
  const filePath = resolve(fileData.path, fileData.name)
380
- if (this.isUnsafeFilename(filePath)) {
377
+ if (isUnsafeFilename(filePath)) {
381
378
  message.error(notSafeMsg)
382
379
  return
383
380
  }
@@ -392,13 +389,16 @@ class Term extends Component {
392
389
  const files = dt.files
393
390
  if (files && files.length) {
394
391
  const arr = Array.from(files)
392
+ const filePaths = arr.map(f => getFilePath(f))
393
+
395
394
  // Check each file path individually
396
- const hasUnsafeFilename = arr.some(f => this.isUnsafeFilename(f.path))
395
+ const hasUnsafeFilename = filePaths.some(path => isUnsafeFilename(path))
397
396
  if (hasUnsafeFilename) {
398
397
  message.error(notSafeMsg)
399
398
  return
400
399
  }
401
- const filesAll = arr.map(f => `"${f.path}"`).join(' ')
400
+
401
+ const filesAll = filePaths.map(path => `"${path}"`).join(' ')
402
402
  this.attachAddon._sendData(filesAll)
403
403
  }
404
404
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electerm/electerm-react",
3
- "version": "1.100.46",
3
+ "version": "1.100.50",
4
4
  "description": "react components src for electerm",
5
5
  "main": "./client/components/main/main.jsx",
6
6
  "license": "MIT",