devoptab: fix nginx listing, fix modifying entry overriding the scheme, fix smb failing to parse url if path isn't set. ftpsrv: workaround clients sending PASS for anon.

This commit is contained in:
ITotalJustice
2025-10-03 07:31:10 +01:00
parent b700fff9ac
commit ca5ea827b2
4 changed files with 43 additions and 10 deletions

View File

@@ -341,7 +341,7 @@ endif()
if (ENABLE_FTPSRV) if (ENABLE_FTPSRV)
FetchContent_Declare(ftpsrv FetchContent_Declare(ftpsrv
GIT_REPOSITORY https://github.com/ITotalJustice/ftpsrv.git GIT_REPOSITORY https://github.com/ITotalJustice/ftpsrv.git
GIT_TAG 7770dab GIT_TAG 7c82402
SOURCE_SUBDIR NONE SOURCE_SUBDIR NONE
) )

View File

@@ -224,8 +224,10 @@ void DevoptabForm::SetupButtons(bool type_change) {
"Hide the mount from being visible as a export option for games and saves."_i18n "Hide the mount from being visible as a export option for games and saves."_i18n
); );
// set default scheme if needed. // set default scheme when creating a new entry.
UpdateSchemeURL(); if (type_change) {
UpdateSchemeURL();
}
const auto callback = this->Add<SidebarEntryCallback>("Save", [this](){ const auto callback = this->Add<SidebarEntryCallback>("Save", [this](){
m_config.name = m_name->GetValue(); m_config.name = m_name->GetValue();

View File

@@ -20,7 +20,9 @@ namespace sphaira::devoptab {
namespace { namespace {
struct DirEntry { struct DirEntry {
std::string name{}; // deprecated because the names can be truncated and really set to anything.
std::string name_deprecated{};
// url decoded href.
std::string href{}; std::string href{};
bool is_dir{}; bool is_dir{};
}; };
@@ -113,14 +115,30 @@ int Device::http_dirlist(const std::string& path, DirEntries& out) {
// todo: if i ever add an xml parser to sphaira, use that instead. // todo: if i ever add an xml parser to sphaira, use that instead.
// todo: for the above, benchmark the parser to ensure its faster than the my code. // todo: for the above, benchmark the parser to ensure its faster than the my code.
std::string_view chunk_view{chunk.data(), chunk.size()}; std::string_view chunk_view{chunk.data(), chunk.size()};
const auto body_start = chunk_view.find("<body");
const auto body_end = chunk_view.rfind("</body>");
const auto table_start = chunk_view.find("<table"); const auto table_start = chunk_view.find("<table");
const auto table_end = chunk_view.rfind("</table>"); const auto table_end = chunk_view.rfind("</table>");
std::string_view table_view{};
// try and find the body, if this doesn't exist, fallback it's not a valid html page.
if (body_start != std::string_view::npos && body_end != std::string_view::npos && body_end > body_start) {
table_view = chunk_view.substr(body_start, body_end - body_start);
}
// try and find the table, massively speeds up parsing if it exists.
// todo: this may cause issues with some web servers that don't use a table for listings.
// todo: if table fails to fine anything, fallback to body_view.
if (table_start != std::string_view::npos && table_end != std::string_view::npos && table_end > table_start) { if (table_start != std::string_view::npos && table_end != std::string_view::npos && table_end > table_start) {
table_view = chunk_view.substr(table_start, table_end - table_start);
}
if (!table_view.empty()) {
const std::string_view href_tag_start = "<a href=\""; const std::string_view href_tag_start = "<a href=\"";
const std::string_view href_tag_end = "\">"; const std::string_view href_tag_end = "\">";
const std::string_view anchor_tag_end = "</a>"; const std::string_view anchor_tag_end = "</a>";
const auto table_view = chunk_view.substr(table_start, table_end - table_start);
size_t pos = 0; size_t pos = 0;
out.reserve(10000); out.reserve(10000);
@@ -138,6 +156,11 @@ int Device::http_dirlist(const std::string& path, DirEntries& out) {
break; // no more href. break; // no more href.
} }
const auto href_name_end = table_view.find('"', href_begin);
if (href_name_end == std::string_view::npos || href_name_end < href_begin || href_name_end > href_end) {
break; // invalid href.
}
const auto name_begin = href_end + href_tag_end.length(); const auto name_begin = href_end + href_tag_end.length();
const auto name_end = table_view.find(anchor_tag_end, name_begin); const auto name_end = table_view.find(anchor_tag_end, name_begin);
if (name_end == std::string_view::npos) { if (name_end == std::string_view::npos) {
@@ -145,7 +168,7 @@ int Device::http_dirlist(const std::string& path, DirEntries& out) {
} }
pos = name_end + anchor_tag_end.length(); pos = name_end + anchor_tag_end.length();
const auto href = url_decode(std::string{table_view.substr(href_begin, href_end - href_begin)}); auto href = url_decode(std::string{table_view.substr(href_begin, href_name_end - href_begin)});
auto name = url_decode(std::string{table_view.substr(name_begin, name_end - name_begin)}); auto name = url_decode(std::string{table_view.substr(name_begin, name_end - name_begin)});
// skip empty names/links, root dir entry and links that are not actual files/dirs (e.g. sorting/filter controls). // skip empty names/links, root dir entry and links that are not actual files/dirs (e.g. sorting/filter controls).
@@ -158,9 +181,9 @@ int Device::http_dirlist(const std::string& path, DirEntries& out) {
continue; continue;
} }
const auto is_dir = name.ends_with('/'); const auto is_dir = href.ends_with('/');
if (is_dir) { if (is_dir) {
name.pop_back(); // remove the trailing '/' href.pop_back(); // remove the trailing '/'
} }
out.emplace_back(name, href, is_dir); out.emplace_back(name, href, is_dir);
@@ -375,8 +398,10 @@ int Device::devoptab_dirnext(void* fd, char *filename, struct stat *filestat) {
filestat->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; filestat->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
} }
// <a href="Compass_2.0.7.1-Release_ScVi3.0.1-Standalone-21-2-0-7-1-1729820977.zip">Compass_2.0.7.1-Release_ScVi3.0.1-Standalone-21..&gt;</a>
filestat->st_nlink = 1; filestat->st_nlink = 1;
std::strcpy(filename, entry.name.c_str()); // std::strcpy(filename, entry.name.c_str());
std::strcpy(filename, entry.href.c_str());
dir->index++; dir->index++;
return 0; return 0;

View File

@@ -123,7 +123,13 @@ bool Device::Mount() {
} }
} }
auto smb2_url = smb2_parse_url(this->smb2, this->config.url.c_str()); // due to a bug in old sphira, i incorrectly prepended the url with smb:// rather than smb2://
auto url = this->config.url;
if (!url.ends_with('/')) {
url += '/';
}
auto smb2_url = smb2_parse_url(this->smb2, url.c_str());
if (!smb2_url) { if (!smb2_url) {
log_write("[SMB2] smb2_parse_url() failed: %s\n", smb2_get_error(this->smb2)); log_write("[SMB2] smb2_parse_url() failed: %s\n", smb2_get_error(this->smb2));
return false; return false;