1
0
mirror of https://github.com/Bayselonarrend/OpenIntegrations.git synced 2025-08-10 22:41:43 +02:00

FTP: Доработка TLS shutdown delay

This commit is contained in:
Anton Titovets
2025-07-31 12:19:38 +03:00
parent f67148246f
commit 08c98b20c9
15 changed files with 8598 additions and 8539 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -198,7 +198,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.52.0", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@@ -445,6 +445,7 @@ dependencies = [
"rustls-pemfile", "rustls-pemfile",
"serde", "serde",
"serde_json", "serde_json",
"socket2",
"socks", "socks",
"suppaftp", "suppaftp",
"webpki-roots", "webpki-roots",
@@ -555,7 +556,7 @@ dependencies = [
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
"windows-sys 0.52.0", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@@ -660,6 +661,16 @@ version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "socket2"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "socks" name = "socks"
version = "0.3.4" version = "0.3.4"

View File

@@ -23,4 +23,5 @@ base64 = "0.22.1"
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
webpki-roots = "1.0.1" webpki-roots = "1.0.1"
rustls = { version = "0.23.28", features = ["ring"] } rustls = { version = "0.23.28", features = ["ring"] }
rustls-pemfile = "2.2.0" rustls-pemfile = "2.2.0"
socket2 = "0.5.10"

View File

@@ -1,9 +1,9 @@
"MAIN ---" "MAIN ---"
linux-vdso.so.1 (0x00007ffe82d8e000) linux-vdso.so.1 (0x00007fff4abf9000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x0000725577200000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007974a2e00000)
libc.so.6 => /lib64/libc.so.6 (0x0000725576e00000) libc.so.6 => /lib64/libc.so.6 (0x00007974a2a00000)
libdl.so.2 => /lib64/libdl.so.2 (0x0000725576a00000) libdl.so.2 => /lib64/libdl.so.2 (0x00007974a2600000)
/lib64/ld-linux-x86-64.so.2 (0x0000725577800000) /lib64/ld-linux-x86-64.so.2 (0x00007974a3400000)
GLIBC_2.2.5 GLIBC_2.2.5
GLIBC_2.3 GLIBC_2.3
GLIBC_2.3.4 GLIBC_2.3.4

View File

@@ -26,4 +26,5 @@ pub struct FtpTlsSettings {
pub use_tls: bool, pub use_tls: bool,
pub accept_invalid_certs: bool, pub accept_invalid_certs: bool,
pub ca_cert_path: Option<String>, pub ca_cert_path: Option<String>,
pub shutdown_delay: u64,
} }

View File

@@ -1,4 +1,4 @@
use std::io::{copy, BufReader, Cursor}; use std::io::{copy, BufReader, Cursor, Write};
use std::net::{SocketAddr, TcpStream}; use std::net::{SocketAddr, TcpStream};
use serde_json::json; use serde_json::json;
use suppaftp::{FtpStream, Mode, RustlsConnector, RustlsFtpStream}; use suppaftp::{FtpStream, Mode, RustlsConnector, RustlsFtpStream};
@@ -7,7 +7,8 @@ use std::str::FromStr;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::Serialize; use serde::Serialize;
use std::string::String; use std::string::String;
use std::thread::sleep;
use std::time::Duration;
use crate::component::configuration::{FtpProxySettings, FtpSettings, FtpTlsSettings}; use crate::component::configuration::{FtpProxySettings, FtpSettings, FtpTlsSettings};
use crate::component::tls_establish; use crate::component::tls_establish;
use crate::component::tcp_establish; use crate::component::tcp_establish;
@@ -156,22 +157,22 @@ impl FtpClient {
} }
} }
pub fn upload_data(&mut self, path: &str, data: &[u8]) -> String { pub fn upload_data(&mut self, path: &str, data: &[u8], tls_delay: u64) -> String {
let mut cursor = Cursor::new(data); let mut cursor = Cursor::new(data);
match self.upload_from_reader(path, &mut cursor) { match self.upload_from_reader(path, &mut cursor, tls_delay) {
Ok(bytes) => json!({"result": true, "bytes": bytes}).to_string(), Ok(bytes) => json!({"result": true, "bytes": bytes}).to_string(),
Err(e) => format_json_error(e) Err(e) => format_json_error(e)
} }
} }
pub fn upload_file(&mut self, path: &str, filepath: &str) -> String { pub fn upload_file(&mut self, path: &str, filepath: &str, tls_delay: u64) -> String {
let file = match std::fs::File::open(filepath) { let file = match std::fs::File::open(filepath) {
Ok(f) => f, Ok(f) => f,
Err(e) => return format_json_error(format!("File error: {}", e)) Err(e) => return format_json_error(format!("File error: {}", e))
}; };
let mut buf_reader = BufReader::new(file); let mut buf_reader = BufReader::new(file);
match self.upload_from_reader(path, &mut buf_reader) { match self.upload_from_reader(path, &mut buf_reader, tls_delay) {
Ok(bytes) => json!({"result": true, "bytes": bytes}).to_string(), Ok(bytes) => json!({"result": true, "bytes": bytes}).to_string(),
Err(e) => format_json_error(e) Err(e) => format_json_error(e)
} }
@@ -193,7 +194,8 @@ impl FtpClient {
fn upload_from_reader<R: std::io::Read>( fn upload_from_reader<R: std::io::Read>(
&mut self, &mut self,
path: &str, path: &str,
reader: &mut R reader: &mut R,
tls_delay: u64
) -> Result<u64, String> { ) -> Result<u64, String> {
match self { match self {
FtpClient::Secure(stream) => { FtpClient::Secure(stream) => {
@@ -204,8 +206,8 @@ impl FtpClient {
let bytes = copy(reader, &mut data_stream) let bytes = copy(reader, &mut data_stream)
.map_err(|e| format!("Upload error: {}", e))?; .map_err(|e| format!("Upload error: {}", e))?;
let _ = std::io::Write::flush(&mut data_stream); let _ = data_stream.flush();
std::thread::sleep(std::time::Duration::from_millis(300)); sleep(Duration::from_millis(tls_delay));
stream.finalize_put_stream(data_stream) stream.finalize_put_stream(data_stream)
.map(|_| bytes) .map(|_| bytes)

View File

@@ -41,7 +41,7 @@ pub fn get_params_amount(num: usize) -> usize {
1 => 0, 1 => 0,
2 => 1, 2 => 1,
3 => 1, 3 => 1,
4 => 3, 4 => 4,
5 => 0, 5 => 0,
6 => 1, 6 => 1,
7 => 1, 7 => 1,
@@ -76,8 +76,9 @@ pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box<dyn
let use_tls = params[0].get_bool().unwrap_or(false); let use_tls = params[0].get_bool().unwrap_or(false);
let accept_invalid_certs = params[1].get_bool().unwrap_or(false); let accept_invalid_certs = params[1].get_bool().unwrap_or(false);
let ca_cert_path = params[2].get_string().unwrap_or("".to_string()); let ca_cert_path = params[2].get_string().unwrap_or("".to_string());
let shutdown_delay = params[3].get_i32().unwrap_or(0);
Box::new(obj.set_tls(use_tls, accept_invalid_certs, &ca_cert_path)) Box::new(obj.set_tls(use_tls, accept_invalid_certs, &ca_cert_path, shutdown_delay as u64))
}, },
5 => { 5 => {
@@ -123,8 +124,13 @@ pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box<dyn
let path = params[1].get_string().unwrap_or("".to_string()); let path = params[1].get_string().unwrap_or("".to_string());
let tls_delay = match &obj.tls_settings{
Some(s) => s.shutdown_delay,
None => 0
};
Box::new(match &mut obj.get_client(){ Box::new(match &mut obj.get_client(){
Ok(c) => c.upload_data(&path, data), Ok(c) => c.upload_data(&path, data, tls_delay),
Err(e) => e.to_string() Err(e) => e.to_string()
}) })
}, },
@@ -133,8 +139,13 @@ pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box<dyn
let filepath = params[0].get_string().unwrap_or("".to_string()); let filepath = params[0].get_string().unwrap_or("".to_string());
let path = params[1].get_string().unwrap_or("".to_string()); let path = params[1].get_string().unwrap_or("".to_string());
let tls_delay = match &obj.tls_settings{
Some(s) => s.shutdown_delay,
None => 0
};
Box::new(match &mut obj.get_client(){ Box::new(match &mut obj.get_client(){
Ok(c) => c.upload_file(&path, &filepath), Ok(c) => c.upload_file(&path, &filepath, tls_delay),
Err(e) => e.to_string() Err(e) => e.to_string()
}) })
@@ -274,7 +285,11 @@ impl AddIn {
} }
pub fn set_tls(&mut self, use_tls: bool, accept_invalid_certs: bool, ca_cert_path: &str) -> String { pub fn set_tls(&mut self
, use_tls: bool
, accept_invalid_certs: bool
, ca_cert_path: &str
, shutdown_delay: u64) -> String {
if self.client.is_some(){ if self.client.is_some(){
return process_error("TLS settings can only be set before the connection is established"); return process_error("TLS settings can only be set before the connection is established");
@@ -285,7 +300,8 @@ impl AddIn {
self.tls_settings = Some(FtpTlsSettings{ self.tls_settings = Some(FtpTlsSettings{
use_tls, use_tls,
accept_invalid_certs, accept_invalid_certs,
ca_cert_path: ca_path ca_cert_path: ca_path,
shutdown_delay
}); });
json!({"result": true}).to_string() json!({"result": true}).to_string()

View File

@@ -3,6 +3,7 @@ use std::net::{SocketAddr, TcpStream};
use std::time::Duration; use std::time::Duration;
use socks::{Socks4Stream, Socks5Stream}; use socks::{Socks4Stream, Socks5Stream};
use base64::{Engine as _, engine::general_purpose}; use base64::{Engine as _, engine::general_purpose};
use socket2::Socket;
use suppaftp::FtpError; use suppaftp::FtpError;
use crate::component::configuration::{FtpProxySettings, FtpSettings}; use crate::component::configuration::{FtpProxySettings, FtpSettings};
@@ -43,6 +44,15 @@ pub fn make_passive_proxy_stream(
let _ = tcp_connection.set_write_timeout(w_timeout); let _ = tcp_connection.set_write_timeout(w_timeout);
let _ = tcp_connection.set_read_timeout(r_timeout); let _ = tcp_connection.set_read_timeout(r_timeout);
let socket = Socket::from(tcp_connection);
match socket.set_linger(Some(Duration::from_secs(10))){
Ok(_) => {},
Err(e) => return Err(FtpError::ConnectionError(
std::io::Error::new(std::io::ErrorKind::Unsupported, e)))
};
let tcp_connection = TcpStream::from(socket);
Ok(tcp_connection) Ok(tcp_connection)
}, },

Binary file not shown.

Binary file not shown.

View File

@@ -21,7 +21,7 @@
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE. // SOFTWARE.

View File

@@ -271,16 +271,18 @@
// Примечание: // Примечание:
// Настройки Tls могут быть установлены только в момент создания соединения: явного, при использовании функции `ОткрытьСоединение`^^ // Настройки Tls могут быть установлены только в момент создания соединения: явного, при использовании функции `ОткрытьСоединение`^^
// или неявного, при передаче настроек // или неявного, при передаче настроек
// `Задержка` может быть увеличена при низкой скорости соединения для избежания проблем с корректным завершением TLS
// //
// Параметры: // Параметры:
// ОтключитьПроверкуСертификатов - Булево - Позволяет работать с некорретными сертификатами, в т.ч. самоподписанными - trust // ОтключитьПроверкуСертификатов - Булево - Позволяет работать с некорретными сертификатами, в т.ч. самоподписанными - trust
// ПутьКСертификату - Строка - Путь к корневому PEM файлу сертификата, если его нет в системном хранилище - cert // ПутьКСертификату - Строка - Путь к корневому PEM файлу сертификата, если его нет в системном хранилище - cert
// Задержка - Число - Задержка перед закрытием соединения для корректного завершения TLS (мс) - delay
// //
// Возвращаемое значение: // Возвращаемое значение:
// Структура Из КлючИЗначение - Структура настроек TLS соединения // Структура Из КлючИЗначение - Структура настроек TLS соединения
Функция ПолучитьНастройкиTls(Знач ОтключитьПроверкуСертификатов, Знач ПутьКСертификату = "") Экспорт Функция ПолучитьНастройкиTls(Знач ОтключитьПроверкуСертификатов, Знач ПутьКСертификату = "", Знач Задержка = 250) Экспорт
Возврат OPI_Компоненты.ПолучитьНастройкиTls(ОтключитьПроверкуСертификатов, ПутьКСертификату); Возврат OPI_Компоненты.ПолучитьНастройкиTls(ОтключитьПроверкуСертификатов, ПутьКСертификату, Задержка);
КонецФункции КонецФункции

View File

@@ -92,7 +92,17 @@
OPI_ПреобразованиеТипов.ПолучитьБулево(ОтключитьВалидацию); OPI_ПреобразованиеТипов.ПолучитьБулево(ОтключитьВалидацию);
OPI_ПреобразованиеТипов.ПолучитьСтроку(ПутьКСертификату); OPI_ПреобразованиеТипов.ПолучитьСтроку(ПутьКСертификату);
Результат = Компонета.SetTLS(ИспользоватьTls, ОтключитьВалидацию, ПутьКСертификату); Задержка = Неопределено;
Если OPI_Инструменты.ПолеКоллекцииСуществует(Tls, "shutdown_delay", Задержка) Тогда
OPI_ПреобразованиеТипов.ПолучитьЧисло(Задержка);
Результат = Компонета.SetTLS(ИспользоватьTls, ОтключитьВалидацию, ПутьКСертификату, Задержка);
Иначе
Результат = Компонета.SetTLS(ИспользоватьTls, ОтключитьВалидацию, ПутьКСертификату);
КонецЕсли;
Результат = OPI_Инструменты.JsonВСтруктуру(Результат); Результат = OPI_Инструменты.JsonВСтруктуру(Результат);
КонецЕсли; КонецЕсли;
@@ -101,12 +111,15 @@
КонецФункции КонецФункции
Функция ПолучитьНастройкиTls(Знач ОтключитьПроверкуСертификатов, Знач ПутьКСертификату = "") Экспорт Функция ПолучитьНастройкиTls(Знач ОтключитьПроверкуСертификатов
, Знач ПутьКСертификату = ""
, Знач Задержка = Неопределено) Экспорт
СтруктураСертификата = Новый Структура; СтруктураСертификата = Новый Структура;
OPI_Инструменты.ДобавитьПоле("use_tls" , Истина , "Булево", СтруктураСертификата); OPI_Инструменты.ДобавитьПоле("use_tls" , Истина , "Булево", СтруктураСертификата);
OPI_Инструменты.ДобавитьПоле("accept_invalid_certs", ОтключитьПроверкуСертификатов, "Булево", СтруктураСертификата); OPI_Инструменты.ДобавитьПоле("accept_invalid_certs", ОтключитьПроверкуСертификатов, "Булево", СтруктураСертификата);
OPI_Инструменты.ДобавитьПоле("ca_cert_path" , ПутьКСертификату , "Строка", СтруктураСертификата); OPI_Инструменты.ДобавитьПоле("ca_cert_path" , ПутьКСертификату , "Строка", СтруктураСертификата);
OPI_Инструменты.ДобавитьПоле("shutdown_delay" , Задержка , "Число" , СтруктураСертификата);
Возврат СтруктураСертификата; Возврат СтруктураСертификата;