Punca sebenar
Penyunting terdahulu memuat naik fail kerjanya ke direktori induk sasaran, yang sering tidak boleh ditulis oleh akaun SSH di bawah /etc atau /var. Penamaan semula SFTP tidak menyediakan laluan sudo yang dibenarkan, semakan konflik terhadap keadaan asas, pengesahan metadata keselamatan atau semantik tulis ganti yang boleh dipercayai. Pengendali ralatnya memadamkan salinan sementara, sekali gus membuang bahan pemulihan walaupun penyelesaian tidak pasti.
Status sesi sebelum ini hanya mendedahkan keadaan sambungan. Tiada pengukuran ICMP atau respons SSH yang disahkan yang menyuap penunjuk terminal.
Protokol penyimpanan
- Helper SSH tetap membuka fail biasa berpautan tunggal menggunakan operasi relatif deskriptor dan
O_NOFOLLOWuntuk setiap komponen laluan. Ia menangkap kandungan, hash SHA-256, peranti/inode, UID, GID, bit kebenaran lengkap, masa pengubahsuaian/perubahan dalam nanosaat dan semua atribut lanjutan yang boleh dibaca. Core mengesahkan hash dan menyahkod UTF-8 dengan ketat, sambil mengekalkan BOM. Setiap dokumen mendapateditIdlegap, yang diskopkan kepada pemalam, sesi terminal dan identiti pelayannya. - Operasi penyediaan tanpa keistimewaan menyelesaikan direktori rumah akaun yang disahkan melalui
pwd.getpwuid(os.getuid()), mencipta$HOME/ch-j-sm/dengan mod0700dan mencipta jurnal pemulihan persendirian yang eksklusif. Direktori rumah yang tidak selamat, ruang kerja pautan simbolik atau ruang kerja milik akaun lain ditolak. - Core memuat naik fail kerja
.tmptersembunyi dengan nama rawak 128-bit melalui SFTP dengan penciptaan eksklusif (wx), mod0600dan tamat masa saluran/muat naik enam puluh saat. Jurnal mengandungi sasaran, keadaan asas asal dan hash kerja yang dijangka; ia tidak mengandungi bukti kelayakan. - Satu exec SSH melaksanakan keseluruhan pemuktamadan, secara pilihan melalui pelaksana sudo sedia ada. Helper membuka dan mengira hash salinan kerja persendirian dengan selamat lalu membilasnya ke cakera. Ia mengunci inode asal, menyemak keadaan asasnya, mencipta fail destinasi eksklusif di sebelah sasaran, menulis semua kandungan, menggunakan dan mengesahkan metadata, menyemak fail asal sekali lagi dan membilas fail pengganti.
os.replacedalam direktori yang sama menggantikan sasaran secara atom. Direktori induk dibilas dan laluan akhir, hash, inode serta metadata disahkan. Laluan asal kekal tersedia sehingga penggantian. Fail kerja tidak pernah dipindahkan merentas sistem fail dan tidak pernah dibuang oleh pemuktamadan.- Selepas Core menerima kejayaan yang disahkan, pembersihan berasingan menyemak semula kandungan akhir dan metadata keselamatan sebelum membuang fail kerja dan jurnal. Kegagalan pembersihan masih melaporkan penyimpanan yang disahkan dengan
recoveryAvailable: true.
Muat naik yang gagal, sudo yang gagal, konflik, ralat metadata atau penggantian yang gagal mengekalkan fail asal dan sebarang bahan yang disediakan. Muat naik yang tidak lengkap dikenal pasti sedemikian dan tidak boleh dipulihkan sebagai dokumen suntingan yang lengkap. Komunikasi SSH yang terputus, status keluar yang tiada, tamat masa dan hasil pemuktamadan yang tidak dijangka dilaporkan sebagai tidak diketahui, tidak pernah sebagai disimpan. Core menyekat penyimpanan lain pada dokumen yang tidak pasti; tiada cubaan semula penggantian automatik.
Metadata, keistimewaan dan sempadan keselamatan
Helper mengekalkan dan mengesahkan UID, GID dan semua bit kebenaran POSIX, termasuk bit boleh laku, setuid, setgid dan sticky. Ia menghasilkan semula atribut lanjutan Linux bait demi bait, termasuk ACL POSIX, capabilities dan label SELinux. Pemilikan dan kandungan fail ditetapkan sebelum atribut keselamatan, kerana penulisan/chown boleh mengosongkan capabilities atau bit kebenaran khas. Atribut destinasi yang diwarisi tetapi tiada pada fail asal dibuang. Masa pengubahsuaian mencerminkan penulisan baharu dan tidak disalin daripada fail asal.
Atribut yang tidak boleh dibaca atau tidak boleh diwakili membatalkan operasi; metadata tidak dibuang secara senyap. Tandatangan IMA/EVM ditolak secara eksplisit kerana menyalin tandatangan integriti yang terikat kepada kandungan/inode akan menjadikannya tidak sah. Pautan simbolik dalam laluan sasaran atau rumah, fail berpautan keras dan fail bukan biasa ditolak. Tiada sandaran tulis ganti di tempat atau tulis ganti SFTP yang lebih lemah digunakan.
Penyimpanan biasa yang boleh ditulis berjalan sebagai akaun SSH. Penyimpanan yang dilindungi memerlukan { sudo: true } yang eksplisit; kata laluan sudo adalah pilihan untuk sudo tanpa kata laluan. Kata laluan disahkan dan dihantar hanya melalui stdin saluran, tidak pernah di dalam arahan, jurnal, fail kerja, pengelog atau ralat jauh. Sesi SSH root menggunakan pelaksana root terus yang sedia ada. Kebenaran yang gagal mengekalkan fail asal dan salinan kerja. Semua penyimpanan yang dilaksanakan sebagai root (SSH root terus atau sudo) juga menolak direktori sasaran/leluhur yang dimiliki atau boleh ditulis oleh akaun lain, atau yang mempunyai ACL akses, dan bukannya mempercayai nama laluan berkeistimewaan yang dikawal oleh akaun lain.
Helper tetap berjalan dengan python3 -I -B: ia mengabaikan laluan Python pengguna, direktori kerja dan pakej tapak pengguna, serta tidak menulis bytecode. Laluan dan argumen JSON dipetik untuk shell dalam Core. Pemalam tidak pernah menerima exec SSH sewenang-wenangnya atau pemegang SFTP. Kotak pasir, CSP, kebenaran manifest, pengesahan kunci hos dan pengesahan kemas kini sedia ada terus digunakan.
Plugin API dan baki integrasi Monaco
UI Monaco/File Manager yang diedarkan secara berasingan tiada dalam checkout ini. Integrasi UInya, gesaan sudo, pengendalian penimbal yang belum disimpan dan terjemahannya tidak dapat dilaksanakan atau diuji di sini. Sumber pemalam yang disertakan ialah pemalam Hash & Checksum. Tiada sumber File Manager pengganti yang direka.
Kaedah sedia ada kekal tersedia. Kaedah/pilihan tambahan didedahkan oleh preload dalam kotak pasir dan masa jalan yang menyemak kebenaran:
const opened = await chjPlugin.files.readText(sessionId, path);
// For a protected read, explicitly pass { sudo: true, sudoPassword }.
const result = await chjPlugin.files.saveText(sessionId, path, editor.getValue(), {
editId: opened.editId,
sudo: true, // Include only after the user authorizes elevation.
sudoPassword // Omit for passwordless sudo; never persist this value.
});
if (result.ok && result.value.status === "saved") {
// Mark this exact submitted editor version as saved. Later edits stay dirty.
} else {
// Keep the Monaco model dirty. Translate result.error.code/status.
// result.error.recoveryId/recoveryPath identify retained working material.
}
await chjPlugin.files.closeText(opened.editId);
const recovery = await chjPlugin.files.listRecovery(sessionId);
const copy = await chjPlugin.files.readRecovery(sessionId, recoveryId);
// Review copy.status and copy.text; open a fresh document before another save.
await chjPlugin.files.cleanupRecovery(sessionId, recoveryId);
// Cleanup rejects anything whose target is not currently confirmed.
Kaedah pemulihan menerima argumen akhir pilihan { sudo: true, sudoPassword } apabila pemeriksaan sasaran memerlukan peningkatan keistimewaan. Ia mengekalkan ruang kerja pengguna yang disahkan walaupun dilaksanakan melalui sudo. Jurnal kekal selepas aplikasi dimulakan semula dan SSH disambung semula; pemulihan tidak pernah mengulangi pemuktamadan secara automatik. Semak penimbal yang dipulihkan terhadap sasaran yang baru dibuka sebelum menyimpannya secara eksplisit.
files.read mengawal pembacaan, pemeriksaan dan pelepasan pemegang. files.write mengawal penyimpanan dan pembersihan pemulihan. writeText masih menolak (reject) apabila gagal untuk pemalam sedia ada; saveText mengembalikan sampul berstruktur { ok, value/error } kerana Electron membuang sifat tersuai pada objek Error yang ditolak. writeText lama dengan tiga argumen boleh menggunakan keadaan asas bagi satu dokumen terbuka. Berbilang dokumen aktif untuk laluan yang sama memerlukan editId; panggilan lama yang samar gagal dengan selamat dan bukannya memilih keadaan asas dokumen lain. Pemalam harus melepaskan pemegang yang tidak digunakan.
UI luaran mesti memaparkan status menyimpan dengan serta-merta, mengekalkan penimbal sebagai belum disimpan apabila gagal, menawarkan sudo hanya selepas kegagalan kebenaran/pengesahan, menunjukkan konflik tanpa menulis ganti dan menawarkan pemulihan selepas kehilangan sambungan atau hasil yang tidak diketahui. Ia mesti menterjemah keadaan ini dalam bahasa Czech, Jerman dan Inggeris. Teks keadaan yang dicadangkan:
| Keadaan | Bahasa Czech | Bahasa Jerman | Bahasa Inggeris |
|---|---|---|---|
| Menyimpan | Ukládání… | Wird gespeichert… | Saving… |
| Disahkan | Uloženo | Gespeichert | Saved |
| Kegagalan | Uložení selhalo | Speichern fehlgeschlagen | Save failed |
| Sudo diperlukan | Vyžadováno oprávnění sudo | sudo-Autorisierung erforderlich | Sudo authorization required |
| Konflik | Původní soubor byl změněn | Originaldatei wurde geändert | Original file changed |
| Terputus | Spojení bylo přerušeno | Verbindung unterbrochen | Connection lost |
| Tidak diketahui | Výsledek uložení není znám | Speicherergebnis unbekannt | Save result unknown |
| Pemulihan | Obnova je dostupná | Wiederherstellung verfügbar | Recovery available |
Definisi kependaman dan kitaran hayat
Ping ialah kependaman yang dilaporkan oleh balasan ICMP echo sebenar di sisi klien kepada IP terselesai yang digunakan oleh SSH. Core memanggil boleh laku ping platform secara tak segerak dengan tatasusunan argumen tetap, tanpa shell atau keperluan permulaan sebagai pentadbir. Argumen Linux, macOS (termasuk ping6) dan Windows dipilih secara berasingan. ICMP yang disekat, boleh laku yang tiada, tamat masa, output yang tidak sah atau balasan Windows yang hanya had atas seperti <1ms menghasilkan nilai tidak tersedia, bukan nombor rekaan.
SSH RTT ialah tempoh monotonik performance.now() bagi permintaan exec true tetap melalui klien SSH disahkan yang sedia ada. Ia merangkumi persediaan saluran, pemprosesan pelayan dan penghantaran respons; ia bukan RTT rangkaian tulen atau tempoh log masuk SSH. Petua alat (tooltip) penunjuk yang diterjemahkan menerangkan perbezaan ini.
Pemantauan bermula sebaik sahaja terminal bersambung. Probe berjalan serentak dan tak segerak, dengan tamat masa permintaan/proses lima saat. Sampel seterusnya dijadualkan dua belas saat selepas sampel sebelumnya selesai, sekali gus mengelakkan pertindihan. Pemutusan sambungan membatalkan ICMP, mengosongkan pemasa, membatalkan kerja SSH yang belum selesai dan mengosongkan nilai. Semakan identiti rekod menghalang sambungan terdahulu daripada menerbitkan nilai selepas sambungan semula. Kegagalan ICMP tidak pernah mengubah keadaan sambungan SSH.
Kependaman dihantar di dalam muatan IPC peristiwa state / ssh:state yang sedia ada:
latency: { pingMs: 24.1, sshRttMs: 31.25, measuredAt: "…" }
Nombor yang tidak tersedia ialah null. Penunjuk terminal padat menggunakan milisaat, teks tidak tersedia yang disetempatkan dan label Czech/Jerman/Inggeris. Ia disembunyikan apabila sambungan terputus. Tiada keupayaan pelaksanaan renderer atau permintaan IPC tambahan diperlukan.
Pengesahan dan had operasi
- Jalankan dari
app/:npm ci, kemudiannpm test. - Hasil setempat akhir: 179 ujian; 163 lulus, 0 gagal, 16 dilangkau. Semua yang dilangkau ialah kes sistem fail Linux pada hos macOS ini.
npm ci, kompilasi sintaks Python dangit diff --checkselesai dengan jayanya. - Ujian merangkumi penyimpanan/pemulihan Core, protokol sudo dan penyuntingan kata laluan, petikan shell POSIX sebenar bagi laluan berniat jahat, konflik, muat naik, pembersihan yang gagal, hasil yang tidak pasti, dokumen serentak, kebenaran IPC dan kitaran hayat kependaman.
- Ujian sistem fail Linux menjalankan titik masuk Python yang dihantar, menggunakan carian direktori rumah akaun ujian persendirian: pemilikan/mod/xattrs, ACL POSIX, pautan simbolik/pautan keras, FIFO, kegagalan muat naik dan metadata, kegagalan penggantian, perlumbaan sasaran, hasil tidak diketahui selepas penggantian dan pemulihan. Penyediaan merentas sistem fail menggunakan
/dev/shmdan sistem fail lain apabila tersedia. Ujian ini dilangkau pada hos bukan Linux; kemudahan ACL/sistem fail berasingan yang tiada dilangkau secara eksplisit. - Tugas GitHub Actions Linux yang ditambah menjalankan suite lengkap dan mengulangi kes sistem fail sebagai root. Aliran kerja ini belum dihantar dari working tree ini.
- Pengesahan setempat dilakukan pada macOS. Sintaks sumber Python disemak dengan boleh laku Python Command Line Tools secara terus. Semakan asap ICMP loopback macOS sebenar mengembalikan
0.071 ms. Tiada pelayan SSH jauh yang aktif, masa jalan Windows, masa jalan Linux, penggunaan SELinux atau UI Monaco luaran diuji secara setempat. - Penyuntingan teks jauh kini memerlukan Linux dan Python 3 dengan sokongan sistem fail/xattr relatif deskriptor. Penterjemah yang tiada akan gagal secara eksplisit. Core ini sengaja menolak metadata, pautan dan konfigurasi direktori yang tidak selamat.
- Penguncian bersifat nasihat: proses yang tidak bekerjasama masih boleh berlumba dalam selang sempit antara semakan keadaan asas terakhir dan penamaan semula atom. Linux tidak menyediakan operasi umum banding-hash-kandungan-dan-ganti yang atom. Semakan mengesan perubahan sebelum selang tersebut; salinan kerja yang dikekalkan menyokong pemulihan selepas itu.
- Data pemulihan kekal pada akaun jauh sehingga pembersihan yang disahkan. Jurnal yang tidak lengkap, berkonflik dan tidak boleh diperiksa tidak pernah dibuang secara senyap. Tiada tamat tempoh automatik fail pemulihan dan tiada pilihan tulis ganti paksa.
npm cimelaporkan 17 dapatan audit kebergantungan (9 sederhana, 8 tinggi). Perubahan ini tidak mengubah kebergantungan atau model kepercayaan kemas kini aplikasi.
Pengguna meminta perubahan dikekalkan dalam working tree sedia ada, kini feature/hash-checksum-plugin; tiada pertukaran cabang atau pembersihan yang tidak berkaitan dilakukan.
Fail yang diubah untuk tugas ini
src/main/files/remoteFileService.jssrc/main/files/remoteEditor.py(baharu)src/main/sessions/sessionManager.jssrc/main/sessions/latencyMonitor.js(baharu)src/main/plugins/pluginRuntime.jssrc/preload/pluginPreload.jssrc/renderer/app.jssrc/renderer/index.htmlsrc/renderer/styles.csssrc/renderer/i18n.jstest/remoteFileService.test.jstest/sessionManager.test.jstest/pluginRuntime.test.jstest/remoteEditor.test.js(baharu)test/remoteEditorProtocol.test.js(baharu)test/remoteEditorLinux.test.js(baharu)test/fixtures/remoteEditorLinux.py(baharu)test/latencyMonitor.test.js(baharu)README.mddocs/remote-editor-latency.md(fail ini)../.github/workflows/remote-editor-tests.yml(baharu)