From 935b17542dab5f10baeb79e48c366079a20d2dc7 Mon Sep 17 00:00:00 2001 From: Pavel Horal Date: Sun, 13 Oct 2024 16:14:56 +0200 Subject: [PATCH] Support for fetching admin list from SFTP source --- README.md | 4 +-- package.json | 3 +- squad-server/utils/admin-lists.js | 50 +++++++++++++++++++++++-------- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 6ab77576..4af236df 100644 --- a/README.md +++ b/README.md @@ -100,8 +100,8 @@ The following section of the configuration contains information about your Squad * `rconPassword` - The RCON password of the server. * `logReaderMode` - `tail` will read from a local log file, `ftp` will read from a remote log file using the FTP protocol, `sftp` will read from a remote log file using the SFTP protocol. * `logDir` - The folder where your Squad logs are saved. Most likely will be `C:/servers/squad_server/SquadGame/Saved/Logs`. -* `ftp` - FTP configuration for reading logs remotely. -* `sftp` - SFTP configuration for reading logs remotely. +* `ftp` - FTP configuration for reading logs remotely. Only required for `ftp` `logReaderMode`. +* `sftp` - SFTP configuration for reading logs remotely. Only required for `sftp` `logReaderMode`. * `adminLists` - Sources for identifying an admins on the server, either remote or local. --- diff --git a/package.json b/package.json index ae90fe46..298aaf9f 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ }, "type": "module", "dependencies": { - "squad-server": "1.0.0" + "squad-server": "1.0.0", + "ssh2-sftp-client": "^11.0.0" }, "devDependencies": { "eslint": "^7.17.0", diff --git a/squad-server/utils/admin-lists.js b/squad-server/utils/admin-lists.js index 9ece8266..934807d9 100644 --- a/squad-server/utils/admin-lists.js +++ b/squad-server/utils/admin-lists.js @@ -1,7 +1,8 @@ import fs from 'fs'; import path from 'path'; -import { fileURLToPath } from 'url'; +import { fileURLToPath, URL } from 'url'; import { Client as FTPClient } from 'basic-ftp'; +import SFTPClient from 'ssh2-sftp-client'; import WritableBuffer from './writable-buffer.js'; import axios from 'axios'; @@ -40,22 +41,45 @@ export default async function fetchAdminLists(adminLists) { `Invalid FTP URI format of ${list.source}. The source must be a FTP URI starting with the protocol. Ex: ftp://username:password@host:21/some/file.txt` ); } - const [loginString, hostPathString] = list.source.substring('ftp://'.length).split('@'); - const [user, password] = loginString.split(':').map((v) => decodeURI(v)); - const pathStartIndex = hostPathString.indexOf('/'); - const remoteFilePath = - pathStartIndex === -1 ? '/' : hostPathString.substring(pathStartIndex); - const [host, port = 21] = hostPathString - .substring(0, pathStartIndex === -1 ? hostPathString.length : pathStartIndex) - .split(':'); - - const buffer = new WritableBuffer(); + const url = new URL(list.source); + console.log(list); + console.log(url); const ftpClient = new FTPClient(); - await ftpClient.access({ host, port, user, password }); - await ftpClient.downloadTo(buffer, remoteFilePath); + await ftpClient.access({ + host: url.hostname, + port: url.port || '21', + user: url.username, + password: url.password + }); + const buffer = new WritableBuffer(); + await ftpClient.downloadTo(buffer, url.pathname); data = buffer.toString('utf8'); break; } + case 'sftp': { + // ex url: sftp//:@:/ + if (!list.source.startsWith('sftp://')) { + throw new Error( + `Invalid SFTP URI format of ${list.source}. The source must be a SFTP URI starting with the protocol. Ex: sftp://username:password@host:22/some/file.txt` + ); + } + const url = new URL(list.source); + const sftpClient = new SFTPClient(); + await sftpClient.connect({ + host: url.hostname, + port: url.port || '22', + username: url.username, + password: url.password + }); + try { + const buffer = new WritableBuffer(); + await sftpClient.get(url.pathname, buffer); + data = buffer.toString('utf8'); + } finally { + sftpClient.end(); + } + break; + } default: throw new Error(`Unsupported AdminList type:${list.type}`); }