SFTP ve výpočtech v TAS 5.7

Návod pro konzultanty, kteří potřebují z výpočtu na úkolu v TAS 5.7 odeslat soubor na SFTP server nebo ho odtud stáhnout. Verze 5.7 nemá samostatné ftp API, přenos souborů se dělá přes objekt curl (knihovna node-libcurl). Objekt axios umí jen HTTP a HTTPS. Postup je ověřený na instanci TAS 5.7.105: čtení proti SFTP serveru (výpis, stažení textového i binárního souboru, chybové stavy, heslo ze secretu), zápis (upload, přejmenování, vytvoření a smazání adresáře, stažení zpět) proti FTP serveru podle kapitoly 9. Mechanismus uploadu a QUOTE příkazů je u obou protokolů stejný, liší se jen názvy příkazů.

Výchozí nastavení curl v 5.7 umí SFTP (SSH, port 22). Pro klasické FTP (port 21) je potřeba ve výpočtu navíc nastavit volbu PROTOCOLS_STR, jinak curl.perform() skončí chybou Unsupported protocol. Postup je v kapitole 9.

Co 5.7 umí a neumí

Potřeba

TAS 5.7

Jak

HTTP/HTTPS REST volání

ano

axios (doporučeno) nebo curl

SFTP – upload, download, výpis, mazání

ano

curl

Klasické FTP (port 21)

ano

curl s volbou PROTOCOLS_STR, viz kapitola 9

Samostatné ftp API (ftp.getFtpClient(...))

ne

od verze 5.12.22, viz FTP a SFTP použití ve výpočtech

SmartEvent „FTP requester"

ne

až v novějších verzích

Chování objektu curl v 5.7

  • Objekt curl je k dispozici jen ve výpočtech úlohy (Task JS) a v identity výpočtech. Ve výpočtu na případu ani v konzoli výpočtů není.
  • Výchozí protokoly jsou HTTP, HTTPS a SFTP. FTP se zapíná volbou PROTOCOLS_STR (kapitola 9).
  • Po prvním curl.perform() se do logu backendu zapíše varování, že CurlApi je zastaralé. Je to jen varování, funkce běží normálně.
  • Kontrola šablony před upgradem (system.validateTemplate(tprocId)) hlásí každé použití curl.* textem „removed, use FtpApi". V 5.7 to ignorujte, je to příprava na upgrade.
  • curl.perform() po dokončení spojení zavře. Pro další požadavek ve stejném výpočtu zavolejte znovu curl.start(), jinak skončí chybou Curl handle is closed.
  • Výsledek perform() je objekt { statusCode, data, headers }. U SFTP je statusCode vždy 0, chyby přicházejí jako výjimka.
  • Výchozí timeout je 60 s. U větších souborů nastavte curl.setOpt('TIMEOUT', 600).

1. Ověření, že server má SFTP v libcurl

Spusťte v testovacím výpočtu na úloze (v konzoli výpočtů objekt curl není):

vars['vysledek'].setValue(curl.info());

Ve výstupu musí být sftp v seznamu protokolů a libssh2 (nebo libssh) mezi knihovnami. Standardní image 5.7 má libcurl/7.86.0 … libssh2/1.10.0 a v protokolech scp, sftp. Pokud chybí, je image bez SSH podpory a je nutné to řešit na úrovni instalace.

2. Přihlašovací údaje

Tři možnosti, od nejjednodušší po nejbezpečnější.

a) V URL

Vhodné jen pro test, heslo je v textu šablony.

curl.setOpt('URL', 'sftp://uzivatel:heslo@sftp.example.com:22/export/soubor.txt');

Speciální znaky v hesle musí být URL-encodované (@ → %40, : → %3A, / → %2F). Jednodušší je použít encodeURIComponent(heslo).

b) Volbou USERPWD

URL je pak bez přihlašovacích údajů a odpadá encodování.

curl.setOpt('URL', 'sftp://sftp.example.com:22/export/soubor.txt');
curl.setOpt('USERPWD', 'uzivatel:heslo');

c) Z tajemství (secret)

Heslo není v kódu šablony. Secret se jmenuje libovolně a jeho hodnota je řetězec uzivatel:heslo. Nastaví se buď v local.js v klíči secrets, nebo jednorázově výpočtem (hodnota se uloží do konfigurace instance, výpočet pak ze šablony odstraňte):

await lib.setSecret('sftpExport', 'uzivatel:heslo');

Ve výpočtu se pak místo curl.perform() volá curl.performSecureAuth(nazevSecretu), které secret načte, nastaví USERPWD a požadavek provede:

curl.setOpt('URL', 'sftp://sftp.example.com:22/export/soubor.txt');
const response = await curl.performSecureAuth('sftpExport');
Do produkce vždy varianta c). Heslo v URL nebo v USERPWD vidí každý, kdo smí editovat šablonu.

Klíč místo hesla

libcurl podporuje volby SSH_PRIVATE_KEYFILE a SSH_PUBLIC_KEYFILE (cesta k souboru na serveru TAS, typicky v mapovaném svazku). Tato varianta není pokrytá testy platformy, funguje na úrovni libcurl.

3. Stažení souboru ze SFTP

Textový soubor, odpověď přijde jako string:

curl.start();
curl.setOpt('URL', 'sftp://sftp.example.com:22/export/data.csv');
curl.setOpt('USERPWD', 'uzivatel:heslo');
curl.setOpt('TIMEOUT', 300);

const { data } = await curl.perform();
vars['csvObsah'].setValue(data);

Binární soubor (PDF, XLSX, ZIP) a uložení do DMS případu. Bez curl.enable('Raw') se obsah poškodí převodem na string (ověřeno: PNG o velikosti 19 156 B dorazil jako řetězec 18 136 znaků):

curl.start();
curl.setOpt('URL', 'sftp://sftp.example.com:22/export/faktura.pdf');
curl.setOpt('USERPWD', 'uzivatel:heslo');
curl.setOpt('TIMEOUT', 300);
curl.enable('Raw');

const { data } = await curl.perform(); // data je Buffer
const dmsfId = await lib.storeAttachment('faktura.pdf', data);

lib.storeAttachment(nazev, Buffer) uloží soubor jako přílohu aktuálního případu a vrátí jeho DMS ID. Pokud ho chcete přiřadit do proměnné typu příloha, nastavte jí vrácené ID.

4. Nahrání souboru na SFTP

Obsah vytvořený ve výpočtu, například CSV:

const csv = 'id;nazev\n1;Test\n';
const datum = new Date().toISOString().slice(0, 10); // 2026-11-09

curl.start();
curl.setOpt('URL', 'sftp://sftp.example.com:22/import/export_' + datum + '.csv');
curl.setOpt('USERPWD', 'uzivatel:heslo');
curl.setOpt('TIMEOUT', 300);
curl.setOpt('UPLOAD', true);
curl.sendBinaryBuffer(Buffer.from(csv, 'utf-8'));

await curl.perform();

Příloha z DMS (proměnná typu příloha, název souboru nebo DMS ID):

const obsah = await storage.getDmsContent(vars['priloha'], 'buffer');   // Buffer

curl.start();
curl.setOpt('URL', 'sftp://sftp.example.com:22/import/' + encodeURIComponent('smlouva.pdf'));
curl.setOpt('USERPWD', 'uzivatel:heslo');
curl.setOpt('TIMEOUT', 600);
curl.setOpt('UPLOAD', true);
curl.sendBinaryBuffer(obsah);

await curl.perform();
Pořadí je důležité: UPLOAD a sendBinaryBuffer před perform. Cílový adresář musí na serveru existovat, SFTP ho při uploadu nevytvoří (viz kapitola 6). Bez práva zápisu skončí perform() chybou Access denied to remote resource. Upload přes UPLOAD + sendBinaryBuffer a stažení zpět byly ověřeny proti FTP serveru (35 B včetně diakritiky, obsah shodný).

5. Výpis adresáře

URL musí končit lomítkem. Výchozí výstup je dlouhý formát jako ls -l; volba DIRLISTONLY vrátí jen názvy, jeden na řádek:

curl.start();
curl.setOpt('URL', 'sftp://sftp.example.com:22/export/');
curl.setOpt('USERPWD', 'uzivatel:heslo');
curl.setOpt('DIRLISTONLY', true);

const { data } = await curl.perform();
const soubory = data.split('\n').filter(n => n && n !== '.' && n !== '..');
return soubory;

Bez DIRLISTONLY přijde výpis ve tvaru -rw------- 1 demo users 379 Sep 19 2023 readme.txt, jeden záznam na řádek, včetně . a ...

6. Mazání, přejmenování, vytvoření adresáře

libcurl umí na SFTP spustit příkazy přes volbu QUOTE (před přenosem) nebo POSTQUOTE (po přenosu). Podporované příkazy: rm, rmdir, rename, mkdir, chmod, ln, symlink. Příkazy se posílají hned po přihlášení, ještě před přechodem do adresáře z URL, proto v nich uvádějte absolutní cesty; relativní cesta se vyhodnotí vůči kořeni účtu. Pokud příkaz na serveru selže (chybějící práva, neexistující cesta), perform() vyhodí Quote command returned error.

Smazání souboru po úspěšném stažení (vzor „zpracuj a ukliď"):

curl.start();
curl.setOpt('URL', 'sftp://sftp.example.com:22/export/data.csv');
curl.setOpt('USERPWD', 'uzivatel:heslo');
curl.setOpt('POSTQUOTE', ['rm /export/data.csv']);

const { data } = await curl.perform();

Přesun do archivu po nahrání:

curl.setOpt('POSTQUOTE', ['rename /import/data.csv /import/archiv/data.csv']);

Vytvoření adresáře před uploadem:

curl.setOpt('QUOTE', ['mkdir /import/2026-11']);

Jen příkazy bez přenosu, například smazat soubor a nic nestahovat:

curl.start();
curl.setOpt('URL', 'sftp://sftp.example.com:22/export/');
curl.setOpt('USERPWD', 'uzivatel:heslo');
curl.setOpt('NOBODY', true);
curl.setOpt('QUOTE', ['rm /export/stary.csv']);
await curl.perform();

7. Ošetření chyb

curl.perform() při chybě vyhodí výjimku s textem chyby libcurl, například Couldn't connect to server, Login denied, Timeout was reached, Unsupported protocol, Access denied to remote resource (zápis bez práv) nebo Quote command returned error. Doporučený vzor:

try {
curl.start();
curl.setOpt('URL', 'sftp://sftp.example.com:22/export/data.csv');
curl.setOpt('USERPWD', 'uzivatel:heslo');
curl.setOpt('TIMEOUT', 120);
const { data } = await curl.perform();
vars['csvObsah'].setValue(data);
} catch (err) {
throw new Error('SFTP stažení selhalo: ' + err.message);
}

Chyba se tak zobrazí uživateli v úloze a zapíše do logu výpočtů.

8. Časté problémy

Projev

Příčina a řešení

Unsupported protocol

URL začíná ftp:// nebo ftps://. 5.7 umí jen sftp://.

Login denied

Špatné heslo nebo neencodované speciální znaky v URL. Použijte USERPWD.

Stažený PDF je poškozený

Chybí curl.enable('Raw'), obsah se převedl na string.

Druhý požadavek ve stejném výpočtu padá

Chyba Curl handle is closed. nebo Cannot add an Easy handle that is closed.: chybí curl.start() před dalším požadavkem, perform() spojení zavírá.

Access denied to remote resource

Účet nemá právo zápisu do cílové cesty nebo cílový adresář neexistuje.

Upload velkého souboru skončí timeoutem

Výchozí limit je 60 s, nastavte TIMEOUT.

Upload do neexistujícího adresáře selže

SFTP adresáře nevytváří, použijte QUOTE s mkdir.

9. Klasické FTP

Pro ftp:// URL je v 5.7 potřeba po curl.start() nastavit volbu PROTOCOLS_STR se seznamem protokolů. Bez ní skončí perform() chybou Unsupported protocol. Ověřeno na 5.7.105: výpis, upload, stažení zpět, MKD, přejmenování, DELE a RMD.

Klasické FTP posílá heslo i data nešifrovaně, používejte ho jen v interní síti. Po upgradu na verzi s ftp API se tento kód přepíše podle kapitoly 10.

Výpis adresáře a upload se liší od SFTP jen protokolem v URL a řádkem navíc:

curl.start();
curl.setOpt('PROTOCOLS_STR', 'ftp,sftp,http,https');
curl.setOpt('URL', 'ftp://ftp.example.com/import/' + encodeURIComponent('data.csv'));
curl.setOpt('USERPWD', 'uzivatel:heslo');
curl.setOpt('TIMEOUT', 300);
curl.setOpt('UPLOAD', true);
curl.sendBinaryBuffer(Buffer.from(csv, 'utf-8'));

const r = await curl.perform(); // r.statusCode je FTP kód odpovědi, např. 226

Příkazy pro QUOTE jsou u FTP klasické FTP příkazy, opět s absolutními cestami:

Operace

SFTP

FTP

vytvoření adresáře

mkdir /import/archiv

MKD /import/archiv

přejmenování / přesun

rename /import/a.csv /import/archiv/a.csv

RNFR /import/a.csv a hned za ním RNTO /import/archiv/a.csv

smazání souboru

rm /import/archiv/a.csv

DELE /import/archiv/a.csv

smazání adresáře

rmdir /import/archiv

RMD /import/archiv

curl.start();
curl.setOpt('PROTOCOLS_STR', 'ftp,sftp,http,https');
curl.setOpt('URL', 'ftp://ftp.example.com/import/');
curl.setOpt('USERPWD', 'uzivatel:heslo');
curl.setOpt('NOBODY', true);
curl.setOpt('QUOTE', ['MKD /import/archiv', 'RNFR /import/data.csv', 'RNTO /import/archiv/data.csv']);
await curl.perform();

10. Co se změní po upgradu

Od verze 5.12.22 je k dispozici ftp API, které umí i klasické FTP, a curl je v novějších verzích odstraněn. Kontrola šablony to před upgradem hlásí. Při přechodu z 5.7 stačí nahradit bloky curl.* voláním odpovídající metody klienta:

const client = ftp.getFtpClient({
protocol: 'sftp', // nebo 'ftp'
host: 'sftp.example.com',
port: 22,
username: 'uzivatel',
password: 'heslo',
});

await client.list('/export');
await client.upload(vars['priloha'], '/import/smlouva.pdf'); // zdroj je DMS soubor
await client.download('/export/data.csv'); // vrátí lokální cestu
await client.exists('/export/data.csv');
await client.delete('/export/data.csv');
await client.rename('/import/a.csv', '/import/archiv/a.csv');
await client.createDirectory('/import/2026-11', true);
await client.removeDirectory('/import/old', true);

Od verze 5.17 lze heslo předat z Trezoru přes ftp.getFtpClientWithVaultPassword(config, vault.get('nazev')). Kompletní popis nového API včetně povolených cest je v článku FTP a SFTP použití ve výpočtech.

FTP a SFTP použití ve výpočtech

Contact

Team assistant (opens in a new tab)

Powered by HelpDocs (opens in a new tab)