initial commit

This commit is contained in:
cy33hc
2026-05-18 20:43:01 -07:00
parent efcafc23fa
commit ad39f39c82
39 changed files with 14683 additions and 0 deletions
+1
View File
@@ -10,6 +10,7 @@ compile_commands.json
CTestTestfile.cmake
_deps
CMakeUserPresets.json
build
# CLion
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+53
View File
@@ -0,0 +1,53 @@
cmake_minimum_required(VERSION 3.5)
project(ezremote-server)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDONT_HAVE_STRUPR")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
set(APP_VERSION "1.00")
add_definitions(-DCPPHTTPLIB_OPENSSL_SUPPORT)
add_definitions(-DCPPHTTPLIB_THREAD_POOL_COUNT=64)
include_directories(
source
)
add_executable(${PROJECT_NAME}.elf
source/http/httplib.cpp
source/server/http_server.cpp
source/clients/archiveorg.cpp
source/clients/baseclient.cpp
source/clients/ftpclient.cpp
source/clients/sftpclient.cpp
source/clients/nfsclient.cpp
source/clients/smbclient.cpp
source/clients/webdav.cpp
source/config.cpp
source/crypt.c
source/fs.cpp
source/getentropy.c
source/orbis_jbc.c
source/main.cpp)
add_self(${PROJECT_NAME}.elf)
add_pkg(${PROJECT_NAME}.elf ${CMAKE_SOURCE_DIR}/data "EZSR00001" "ezRemote Server" "01.00" 32 0)
target_compile_definitions(${PROJECT_NAME}.elf PRIVATE EZREMOTE_VERSION=${APP_VERSION} CPPHTTPLIB_THREAD_POOL_COUNT=64)
target_link_libraries(${PROJECT_NAME}.elf
dbglogger
z
crypto
ssl
json-c
jbc
smb2
ssh2
nfs
kernel_sys
SceSysmodule
SceNet
SceSystemService
)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

+110
View File
@@ -0,0 +1,110 @@
#ifndef EZ_BASE64_H_
#define EZ_BASE64_H_
#include <string>
class Base64
{
public:
static int Encode(unsigned char *input, size_t in_len, std::string &out)
{
static constexpr char sEncodingTable[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'};
size_t out_len = 4 * ((in_len + 2) / 3);
out.resize(out_len);
size_t i;
char *p = const_cast<char *>(out.c_str());
for (i = 0; i < in_len - 2; i += 3)
{
*p++ = sEncodingTable[(input[i] >> 2) & 0x3F];
*p++ = sEncodingTable[((input[i] & 0x3) << 4) | ((int)(input[i + 1] & 0xF0) >> 4)];
*p++ = sEncodingTable[((input[i + 1] & 0xF) << 2) | ((int)(input[i + 2] & 0xC0) >> 6)];
*p++ = sEncodingTable[input[i + 2] & 0x3F];
}
if (i < in_len)
{
*p++ = sEncodingTable[(input[i] >> 2) & 0x3F];
if (i == (in_len - 1))
{
*p++ = sEncodingTable[((input[i] & 0x3) << 4)];
*p++ = '=';
}
else
{
*p++ = sEncodingTable[((input[i] & 0x3) << 4) | ((int)(input[i + 1] & 0xF0) >> 4)];
*p++ = sEncodingTable[((input[i + 1] & 0xF) << 2)];
}
*p++ = '=';
}
return 1;
}
static int Encode(const std::string &input, std::string &out)
{
return Encode((unsigned char*)input.data(), input.size(), out);
}
static int Decode(const std::string &input, std::string &out)
{
static constexpr unsigned char kDecodingTable[] = {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64};
size_t in_len = input.size();
if (in_len % 4 != 0)
return 0;
size_t out_len = in_len / 4 * 3;
if (input[in_len - 1] == '=')
out_len--;
if (input[in_len - 2] == '=')
out_len--;
out.resize(out_len);
for (size_t i = 0, j = 0; i < in_len;)
{
uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6);
if (j < out_len)
out[j++] = (triple >> 2 * 8) & 0xFF;
if (j < out_len)
out[j++] = (triple >> 1 * 8) & 0xFF;
if (j < out_len)
out[j++] = (triple >> 0 * 8) & 0xFF;
}
return 1;
}
};
#endif
+126
View File
@@ -0,0 +1,126 @@
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <lexbor/dom/interfaces/node.h>
#include <fstream>
#include <map>
#include "config.h"
#include "clients/remote_client.h"
#include "clients/archiveorg.h"
#include "util.h"
using httplib::Client;
using httplib::Headers;
using httplib::Result;
struct InsensitiveCompare
{
bool operator()(const std::string &a, const std::string &b) const
{
return strcasecmp(a.c_str(), b.c_str()) < 0;
}
};
static std::set<std::string, InsensitiveCompare> ignore_cookie_keys = {"path", "expires", "max-age", "domain", "secure"};
std::string ArchiveOrgClient::GenerateRandomId(const int len)
{
static const char alphanum[] = "0123456789abcdef";
std::string tmp_s;
tmp_s.reserve(len);
for (int i = 0; i < len; ++i) {
tmp_s += alphanum[rand() % (sizeof(alphanum) - 1)];
}
return tmp_s;
}
int ArchiveOrgClient::Connect(const std::string &url, const std::string &username, const std::string &password)
{
this->host_url = url;
size_t scheme_pos = url.find("://");
size_t root_pos = url.find("/", scheme_pos + 3);
if (root_pos != std::string::npos)
{
this->host_url = url.substr(0, root_pos);
this->base_path = url.substr(root_pos);
}
client = new httplib::Client(this->host_url);
client->set_keep_alive(true);
client->set_follow_location(true);
client->set_connection_timeout(30);
client->set_read_timeout(30);
client->enable_server_certificate_verification(false);
this->cookies = {
{"donation-identifier", GenerateRandomId(32)},
{"test-cookie", "1"},
{"abtest-identifier", GenerateRandomId(32)}
};
if (username.length() > 0)
return Login(username, password);
this->connected = true;
return 1;
}
int ArchiveOrgClient::Login(const std::string &username, const std::string &password)
{
std::string url = std::string("/account/login");
Headers headers = {{ "User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0"}};
SetCookies(headers);
MultipartFormDataItems items = {
{"username", username, "", ""},
{"password", password, "", ""},
{"remember", "true", "", ""},
{"referer", "https://archive.org/", "", ""},
{"login", "true", "", ""},
{"submit_by_js", "true", "", ""}};
if (auto res = client->Post(url, headers, items))
{
if (HTTP_SUCCESS(res->status))
{
if (res->has_header("Set-Cookie"))
{
int cookies_count = res->get_header_value_count("Set-Cookie");
for (int i = 0; i < cookies_count; i++)
{
std::string cookie_str = res->get_header_value("Set-Cookie", i);
std::vector<std::string> cookies = Util::Split(cookie_str, ";");
for (std::vector<std::string>::iterator it = cookies.begin(); it != cookies.end();)
{
std::vector<std::string> cookie = Util::Split(*it, "=");
std::string key = Util::Trim(cookie[0], " ");
if (ignore_cookie_keys.find(key) == ignore_cookie_keys.end())
{
if (cookie.size() > 1)
this->cookies[key] = Util::Trim(cookie[1], " ");
else
this->cookies[key] = "";
}
++it;
}
}
this->connected = true;
return 1;
}
else
{
return 0;
}
}
else
{
return 0;
}
}
else
{
return 0;
}
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef EZ_ARCHIVEORG_H
#define EZ_ARCHIVEORG_H
#include <string>
#include <vector>
#include "clients/remote_client.h"
#include "clients/baseclient.h"
class ArchiveOrgClient : public BaseClient
{
public:
int Connect(const std::string &url, const std::string &username, const std::string &password);
private:
int Login(const std::string &username, const std::string &password);
std::string GenerateRandomId(const int len);
};
#endif
+169
View File
@@ -0,0 +1,169 @@
#include <fstream>
#include <curl/curl.h>
#include <sys/time.h>
#include <orbis/SystemService.h>
#include "clients/remote_client.h"
#include "clients/baseclient.h"
#include "config.h"
#include "util.h"
using httplib::Client;
using httplib::DataSink;
using httplib::Headers;
using httplib::Result;
BaseClient::BaseClient(){};
BaseClient::~BaseClient()
{
if (client != nullptr)
delete client;
};
int BaseClient::SetCookies(Headers &headers)
{
if (this->cookies.size() > 0)
{
std::string cookie;
for (std::map<std::string, std::string>::iterator it = this->cookies.begin(); it != this->cookies.end();)
{
cookie.append(it->first).append("=").append(it->second);
if (std::next(it, 1) != this->cookies.end())
{
cookie.append("; ");
}
++it;
}
headers.emplace("Cookie", cookie);
}
return 1;
}
int BaseClient::Connect(const std::string &url, const std::string &username, const std::string &password)
{
this->host_url = url;
size_t scheme_pos = url.find("://");
size_t root_pos = url.find("/", scheme_pos + 3);
if (root_pos != std::string::npos)
{
this->host_url = url.substr(0, root_pos);
this->base_path = url.substr(root_pos);
}
client = new httplib::Client(this->host_url);
if (username.length() > 0)
client->set_basic_auth(username, password);
client->set_keep_alive(true);
client->set_follow_location(true);
client->set_connection_timeout(30);
client->set_read_timeout(30);
client->enable_server_certificate_verification(false);
this->connected = true;
return 1;
}
int BaseClient::Get(const std::string &outputfile, const std::string &path, uint64_t offset)
{
std::ofstream file_stream;
if (offset > 0)
{
file_stream.open(outputfile, std::ofstream::out | std::ofstream::binary | std::ofstream::app);
}
else
{
file_stream.open(outputfile, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
}
*g_bytes_transfered = offset;
Headers headers;
SetCookies(headers);
if (offset > 0)
{
char range_header[128];
sprintf(range_header, "bytes=%lu-", offset);
headers.emplace("Range", range_header);
}
if (auto res = client->Get(GetFullPath(path), headers,
[&](const char *data, size_t data_length)
{
file_stream.write(data, data_length);
*g_bytes_transfered = *g_bytes_transfered + data_length;
sceSystemServicePowerTick();
return true;
}))
{
file_stream.close();
return 1;
}
else
{
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
}
return 0;
}
int BaseClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset)
{
char range_header[64];
sprintf(range_header, "bytes=%lu-%lu", offset, offset + size - 1);
Headers headers = {{"Range", range_header}};
SetCookies(headers);
size_t bytes_read = 0;
if (auto res = client->Get(GetFullPath(path), headers,
[&](const char *data, size_t data_length)
{
bytes_read += data_length;
bool ok = sink.write(data, data_length);
sceSystemServicePowerTick();
return ok;
}))
{
return bytes_read == size;
}
else
{
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
}
return 0;
}
std::string BaseClient::GetPath(std::string ppath1, std::string ppath2)
{
std::string path1 = ppath1;
std::string path2 = ppath2;
path1 = Util::Trim(Util::Trim(path1, " "), "/");
path2 = Util::Trim(Util::Trim(path2, " "), "/");
path1 = this->base_path + ((this->base_path.length() > 0) ? "/" : "") + path1 + "/" + path2;
if (path1[0] != '/')
path1 = "/" + path1;
return path1;
}
std::string BaseClient::GetFullPath(std::string ppath1)
{
std::string path1 = ppath1;
path1 = Util::Trim(Util::Trim(path1, " "), "/");
path1 = this->base_path + "/" + path1;
Util::ReplaceAll(path1, "//", "/");
return path1;
}
const char *BaseClient::LastResponse()
{
return this->response;
}
int BaseClient::Quit()
{
if (client != nullptr)
{
delete client;
client = nullptr;
}
return 1;
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef BASESERVER_H
#define BASESERVER_H
#include <string>
#include <vector>
#include <map>
#include "clients/remote_client.h"
#define HTTP_SUCCESS(x) (x >= 200 && x < 300)
class BaseClient : public RemoteClient
{
public:
BaseClient();
~BaseClient();
int Connect(const std::string &url, const std::string &username, const std::string &password);
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
std::string GetPath(std::string path1, std::string path2);
std::string GetFullPath(std::string path1);
const char *LastResponse();
int Quit();
static int DownloadProgressCallback(void* ptr, double dTotalToDownload, double dNowDownloaded, double dTotalToUpload, double dNowUploaded);
protected:
int SetCookies(httplib::Headers &headers);
httplib::Client *client;
std::string base_path;
std::string host_url;
char response[512];
bool connected = false;
std::map<std::string, std::string> cookies;
};
#endif
File diff suppressed because it is too large Load Diff
+128
View File
@@ -0,0 +1,128 @@
#ifndef EZ_FTPCLIENT_H
#define EZ_FTPCLIENT_H
#include <sys/socket.h>
#include <arpa/inet.h>
#include <time.h>
#include <string>
#include <vector>
#include "clients/remote_client.h"
#define FTP_CLIENT_MAX_FILENAME_LEN 255
typedef int (*FtpCallbackXfer)(int64_t xfered, void *arg);
struct ftphandle
{
char *cput, *cget;
int handle;
int cavail, cleft;
char *buf;
int dir;
ftphandle *ctrl;
int cmode;
int64_t xfered;
int64_t xfered1;
int64_t cbbytes;
char response[512];
int64_t offset;
bool correctpasv;
FtpCallbackXfer xfercb;
void *cbarg;
bool is_connected;
};
class FtpClient : public RemoteClient
{
public:
enum accesstype
{
dir = 1,
dirverbose,
dirmlsd,
fileread,
filewrite,
filereadappend,
filewriteappend
};
enum transfermode
{
ascii = 'A',
image = 'I'
};
enum connmode
{
pasv = 1,
port
};
enum attributes
{
directory = 1,
readonly = 2
};
FtpClient();
~FtpClient();
int Connect(const std::string &url, const std::string &user, const std::string &pass);
void SetConnmode(connmode mode);
int Site(const std::string &cmd);
int Raw(const std::string &cmd);
int SysType(char *buf, int max);
int Mkdir(const std::string &path);
int Chdir(const std::string &path);
int Cdup();
int Rmdir(const std::string &path);
int Size(const std::string &path, uint64_t *size);
int Get(const std::string &outputfile, const std::string &path, uint64_t offset = 0);
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
int GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset);
int GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset);
int Put(const std::string &inputfile, const std::string &path, uint64_t offset = 0);
int Rename(const std::string &src, const std::string &dst);
int Delete(const std::string &path);
int Head(const std::string &path, void *buffer, uint64_t len);
void *Open(const std::string &path, int flags);
void Close(void *fp);
void SetCallbackXferFunction(FtpCallbackXfer pointer);
void SetCallbackArg(void *arg);
void SetCallbackBytes(int64_t bytes);
bool Noop();
bool Ping();
bool FileExists(const std::string &path);
bool IsConnected();
char *LastResponse();
long GetIdleTime();
int Quit();
private:
ftphandle *mp_ftphandle;
struct tm cur_time;
timeval tick;
char server[128];
int server_port;
int FtpSendCmd(const std::string &cmd, const std::string &expected_resp, ftphandle *nControl);
ftphandle *RawOpen(const std::string &path, accesstype type, transfermode mode);
int RawClose(ftphandle *handle);
int RawWrite(void *buf, int len, ftphandle *handle);
int RawRead(void *buf, int max, ftphandle *handle);
int ReadResponse(const std::string &c, ftphandle *nControl);
int Readline(char *buf, int max, ftphandle *nControl);
int Writeline(char *buf, int len, ftphandle *nData);
void ClearHandle();
int FtpOpenPasv(ftphandle *nControl, ftphandle **nData, transfermode mode, int dir, std::string &cmd);
int FtpOpenPort(ftphandle *nControl, ftphandle **nData, transfermode mode, int dir, std::string &cmd);
int FtpAcceptConnection(ftphandle *nData, ftphandle *nControl);
int CorrectPasvResponse(int *v);
int FtpAccess(const std::string &path, accesstype type, transfermode mode, ftphandle *nControl, ftphandle **nData);
int FtpXfer(const std::string &localfile, const std::string &path, ftphandle *nControl, accesstype type, transfermode mode);
int FtpWrite(void *buf, int len, ftphandle *nData);
int FtpRead(void *buf, int max, ftphandle *nData);
int FtpClose(ftphandle *nData);
};
#endif
+201
View File
@@ -0,0 +1,201 @@
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <cstring>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <inttypes.h>
#include <errno.h>
#include <orbis/SystemService.h>
#include "clients/nfsclient.h"
#include "config.h"
#include "fs.h"
#define BUF_SIZE 1048576
NfsClient::NfsClient()
{
}
NfsClient::~NfsClient()
{
}
int NfsClient::Connect(const std::string &url, const std::string &user, const std::string &pass)
{
nfs = nfs_init_context();
if (nfs == nullptr)
{
sprintf(response, "%s", "Failed to init nfs context");
return 0;
}
struct nfs_url *nfsurl = nfs_parse_url_full(nfs, url.c_str());
if (nfsurl == nullptr) {
sprintf(response, "%s", nfs_get_error(nfs));
nfs_destroy_context(nfs);
return 0;
}
std::string export_path = std::string(nfsurl->path) + nfsurl->file;
int ret = nfs_mount(nfs, nfsurl->server, export_path.c_str());
if (ret != 0)
{
sprintf(response, "%s", nfs_get_error(nfs));
nfs_destroy_url(nfsurl);
nfs_destroy_context(nfs);
nfs = nullptr;
return 0;
}
nfs_destroy_url(nfsurl);
connected = true;
return 1;
}
/*
* LastResponse - return a pointer to the last response received
*/
const char *NfsClient::LastResponse()
{
return (const char *)response;
}
/*
* Quit - disconnect from remote
*
* return 1 if successful, 0 otherwise
*/
int NfsClient::Quit()
{
if (nfs != nullptr)
{
nfs_umount(nfs);
nfs_destroy_context(nfs);
nfs = nullptr;
}
connected = false;
return 1;
}
/*
* Get - issue a GET command and write received data to output
*
* return 1 if successful, 0 otherwise
*/
int NfsClient::Get(const std::string &outputfile, const std::string &ppath, uint64_t offset)
{
struct nfsfh *nfsfh = nullptr;
int ret = nfs_open(nfs, ppath.c_str(), 0400, &nfsfh);
if (ret != 0)
{
sprintf(response, "%s", nfs_get_error(nfs));
return 0;
}
FILE* out = NULL;
if (offset > 0)
{
out = FS::Append(outputfile);
}
else
{
out = FS::Create(outputfile);
}
if (out == NULL)
{
// sprintf(response, "%s", lang_strings[STR_FAILED]);
return 0;
}
void *buff = malloc(BUF_SIZE);
int count = 0;
*g_bytes_transfered = offset;
if (offset > 0)
{
nfs_lseek(nfs, nfsfh, offset, SEEK_SET, NULL);
}
while ((count = nfs_read(nfs, nfsfh, BUF_SIZE, buff)) > 0)
{
if (count < 0)
{
sprintf(response, "%s", nfs_get_error(nfs));
FS::Close(out);
nfs_close(nfs, nfsfh);
free((void*)buff);
return 0;
}
FS::Write(out, buff, count);
*g_bytes_transfered += count;
sceSystemServicePowerTick();
}
FS::Close(out);
nfs_close(nfs, nfsfh);
free((void*)buff);
return 1;
}
int NfsClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset)
{
struct nfsfh *nfsfh = nullptr;
int ret = nfs_open(nfs, path.c_str(), 0400, &nfsfh);
if (ret != 0)
{
return 0;
}
ret = this->GetRange((void *)nfsfh, sink, size, offset);
nfs_close(nfs, nfsfh);
return ret;
}
int NfsClient::GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset)
{
struct nfsfh *nfsfh = (struct nfsfh *)fp;
int ret = nfs_lseek(nfs, nfsfh, offset, SEEK_SET, NULL);
if (ret != 0)
{
return 0;
}
void *buff = malloc(BUF_SIZE);
int count = 0;
size_t bytes_remaining = size;
do
{
size_t bytes_to_read = std::min<size_t>(BUF_SIZE, bytes_remaining);
count = nfs_read(nfs, nfsfh, bytes_to_read, buff);
if (count > 0)
{
bytes_remaining -= count;
bool ok = sink.write((char *)buff, count);
if (!ok)
{
free((void *)buff);
return 0;
}
}
else
{
break;
}
} while (1);
free((void *)buff);
return 1;
}
+33
View File
@@ -0,0 +1,33 @@
#ifndef NFSCLIENT_H
#define NFSCLIENT_H
#include <sys/socket.h>
#include <arpa/inet.h>
#include <time.h>
#include <string>
#include <vector>
#include "nfsc/libnfs.h"
#include "nfsc/libnfs-raw.h"
#include "nfsc/libnfs-raw-mount.h"
#include "clients/remote_client.h"
class NfsClient : public RemoteClient
{
public:
NfsClient();
~NfsClient();
int Connect(const std::string &url, const std::string &user, const std::string &pass);
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
int GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset);
const char *LastResponse();
int Quit();
private:
int _Rmdir(const std::string &ppath);
struct nfs_context *nfs;
char response[1024];
bool connected = false;
};
#endif
+34
View File
@@ -0,0 +1,34 @@
#ifndef REMOTECLIENT_H
#define REMOTECLIENT_H
#include <string>
#include <vector>
#include "http/httplib.h"
enum ClientType
{
CLIENT_TYPE_FTP,
CLIENT_TYPE_SFTP,
CLIENT_TYPE_SMB,
CLIENT_TYPE_WEBDAV,
CLIENT_TYPE_HTTP_SERVER,
CLIENT_TYPE_NFS,
CLIENT_TYPE_FILEHOST,
CLINET_TYPE_UNKNOWN
};
using namespace httplib;
class RemoteClient
{
public:
RemoteClient(){};
virtual ~RemoteClient(){};
virtual int Connect(const std::string &url, const std::string &username, const std::string &password) = 0;
virtual int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0) = 0;
virtual int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset) = 0;
virtual const char *LastResponse() = 0;
virtual int Quit() = 0;
};
#endif
+314
View File
@@ -0,0 +1,314 @@
#include <sys/socket.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <time.h>
#include <orbis/SystemService.h>
#include "clients/remote_client.h"
#include "clients/sftpclient.h"
#include "fs.h"
#include "config.h"
#define FTP_CLIENT_BUFSIZ 1048576
SFTPClient::SFTPClient()
{
session = nullptr;
sftp_session = nullptr;
sock = 0;
};
SFTPClient::~SFTPClient(){};
int SFTPClient::Connect(const std::string &url, const std::string &username, const std::string &password)
{
int port = 22;
std::string host = url.substr(7);
size_t colon_pos = host.find(":");
if (colon_pos != std::string::npos)
{
port = std::atoi(host.substr(colon_pos + 1).c_str());
host = host.substr(0, colon_pos);
}
struct hostent *he;
struct in_addr **addr_list;
char ip[20];
int i;
if (strcmp(host.c_str(), "localhost") == 0)
{
sprintf(ip, "%s", "127.0.0.1");
}
else
{
if ((he = gethostbyname(host.c_str())) == NULL)
{
return 0;
}
addr_list = (struct in_addr **)he->h_addr_list;
for (i = 0; addr_list[i] != NULL; i++)
{
strcpy(ip, inet_ntoa(*addr_list[i]));
break;
}
}
in_addr dst_addr;
sockaddr_in server_addr;
int on = 1;
int32_t retval;
memset(&server_addr, 0, sizeof(server_addr));
inet_pton(AF_INET, ip, (void *)&dst_addr);
server_addr.sin_addr = dst_addr;
server_addr.sin_port = htons(port);
server_addr.sin_family = AF_INET;
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
retval = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on));
int const size = FTP_CLIENT_BUFSIZ;
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) == -1)
{
close(sock);
return 0;
}
if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) == -1)
{
close(sock);
return 0;
}
if (connect(sock, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr_in)) != 0)
{
sprintf(this->response, "%s", "Failed to connect!");
return 0;
}
/* Create a session instance
*/
session = libssh2_session_init();
libssh2_session_set_blocking(session, 1);
libssh2_keepalive_config(session, 1, 5);
if (!session)
{
sprintf(this->response, "Failed to connect");
return 0;
}
/* ... start it up. This will trade welcome banners, exchange keys,
* and setup crypto, compression, and MAC layers
*/
usleep(100000);
int rc = libssh2_session_handshake(session, sock);
if (rc)
{
sprintf(this->response, "Failed SSL handshake %d", rc);
return 0;
}
/* At this point we havn't yet authenticated. The first thing to do
* is check the hostkey's fingerprint against our known hosts Your app
* may have it hard coded, may go to a file, may present it to the
* user, that's your call
*/
const char *fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
/* check what authentication methods are available */
char *userauthlist = libssh2_userauth_list(session, username.c_str(), username.length());
int auth_pw = 0;
if (strstr(userauthlist, "password") != NULL)
{
auth_pw |= 1;
}
if (strstr(userauthlist, "keyboard-interactive") != NULL)
{
auth_pw |= 2;
}
if (strstr(userauthlist, "publickey") != NULL)
{
auth_pw |= 4;
}
bool use_identity = password.find("file://") != std::string::npos;
if (auth_pw & 1 && !use_identity)
{
/* We could authenticate via password */
if (libssh2_userauth_password(session, username.c_str(), password.c_str()))
{
sprintf(this->response, "%s", "Authentication by password failed!");
goto shutdown;
}
}
else if (auth_pw & 4 && use_identity)
{
/* Or by public key */
std::string publickey = password.substr(7) + "/id_rsa.pub";
std::string privatekey = password.substr(7) + "/id_rsa";
if (!FS::FileExists(publickey.c_str()))
{
sprintf(response, "SSH public key %s is not found", publickey.c_str());
goto shutdown;
}
if (!FS::FileExists(privatekey.c_str()))
{
sprintf(response, "SSH private key %s is not found", privatekey.c_str());
goto shutdown;
}
if (libssh2_userauth_publickey_fromfile(session, username.c_str(), publickey.c_str(), privatekey.c_str(), ""))
{
sprintf(this->response, "%s", "Authentication by public key failed!");
goto shutdown;
}
}
else
{
sprintf(this->response, "%s", "No supported authentication methods found!");
goto shutdown;
}
sftp_session = libssh2_sftp_init(session);
this->connected = true;
return 1;
shutdown:
libssh2_session_disconnect(session, "Normal Shutdown");
libssh2_session_free(session);
close(sock);
libssh2_exit();
session = nullptr;
sock = 0;
return 0;
}
int SFTPClient::Get(const std::string &outputfile, const std::string &path, uint64_t offset)
{
LIBSSH2_SFTP_HANDLE *sftp_handle = libssh2_sftp_open(sftp_session, path.c_str(), LIBSSH2_FXF_READ, 0);
if (!sftp_handle)
{
sprintf(response, "Unable to open file with SFTP: %ld", libssh2_sftp_last_error(sftp_session));
return 0;
}
FILE* out = NULL;
if (offset > 0)
{
out = FS::Append(outputfile);
}
else
{
out = FS::Create(outputfile);
}
if (out == NULL)
{
// sprintf(response, "%s", lang_strings[STR_FAILED]);
return 0;
}
char *buff = (char *)malloc(FTP_CLIENT_BUFSIZ);
int rc, count = 0;
*g_bytes_transfered = offset;
if (offset > 0)
{
libssh2_sftp_seek64(sftp_handle, offset);
}
do
{
rc = libssh2_sftp_read(sftp_handle, buff, FTP_CLIENT_BUFSIZ);
if (rc > 0)
{
*g_bytes_transfered += rc;
FS::Write(out, buff, rc);
sceSystemServicePowerTick();
}
else
{
break;
}
} while (1);
free((char *)buff);
FS::Close(out);
libssh2_sftp_close(sftp_handle);
return 1;
}
int SFTPClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset)
{
LIBSSH2_SFTP_HANDLE *sftp_handle = libssh2_sftp_open(sftp_session, path.c_str(), LIBSSH2_FXF_READ, 0);
if (!sftp_handle)
{
sprintf(response, "Unable to open file with SFTP: %ld", libssh2_sftp_last_error(sftp_session));
return 0;
}
int ret = this->GetRange((void *)sftp_handle, sink, size, offset);
libssh2_sftp_close(sftp_handle);
return ret;
}
int SFTPClient::GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset)
{
LIBSSH2_SFTP_HANDLE *sftp_handle = (LIBSSH2_SFTP_HANDLE *)fp;
libssh2_sftp_seek64(sftp_handle, offset);
char *buff = (char *)malloc(FTP_CLIENT_BUFSIZ);
int rc, count = 0;
size_t bytes_remaining = size;
do
{
size_t bytes_to_read = std::min<size_t>(FTP_CLIENT_BUFSIZ, bytes_remaining);
rc = libssh2_sftp_read(sftp_handle, buff, bytes_to_read);
if (rc > 0)
{
bytes_remaining -= rc;
bool ok = sink.write(buff, rc);
if (!ok)
{
free((char *)buff);
return 0;
}
}
else
{
break;
}
} while (1);
free((char *)buff);
return 1;
}
const char *SFTPClient::LastResponse()
{
return this->response;
}
int SFTPClient::Quit()
{
if (sftp_session != nullptr)
libssh2_sftp_shutdown(sftp_session);
if (session != nullptr)
{
libssh2_session_disconnect(session, "Normal Shutdown");
libssh2_session_free(session);
close(sock);
libssh2_exit();
}
session = nullptr;
sftp_session = nullptr;
sock = 0;
return 1;
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef EZ_SFTPCLIENT_H
#define EZ_SFTPCLIENT_H
#include <libssh2.h>
#include <libssh2_sftp.h>
#include <string>
#include <vector>
#include "clients/remote_client.h"
class SFTPClient : public RemoteClient
{
public:
SFTPClient();
~SFTPClient();
int Connect(const std::string &url, const std::string &username, const std::string &password);
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
int GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset);
const char *LastResponse();
int Quit();
protected:
LIBSSH2_SESSION *session;
LIBSSH2_SFTP *sftp_session;
int sock;
char response[512];
bool connected = false;
};
#endif
+196
View File
@@ -0,0 +1,196 @@
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <cstring>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <fcntl.h>
#include <inttypes.h>
#include <errno.h>
#include <orbis/SystemService.h>
#include "config.h"
#include "fs.h"
#include "clients/smbclient.h"
#include "util.h"
SmbClient::SmbClient()
{
}
SmbClient::~SmbClient()
{
}
int SmbClient::Connect(const std::string &url, const std::string &user, const std::string &pass)
{
struct smb2_url *smb_url;
smb2 = smb2_init_context();
if (smb2 == NULL)
{
sprintf(response, "Failed to init SMB context");
return 0;
}
smb_url = smb2_parse_url(smb2, url.c_str());
if (smb_url == NULL || smb_url->share == NULL || strlen(smb_url->share) == 0)
{
sprintf(response, "Invalid SMB Url");
return 0;
}
if (pass.length() > 0)
smb2_set_password(smb2, pass.c_str());
smb2_set_security_mode(smb2, SMB2_NEGOTIATE_SIGNING_ENABLED);
smb2_set_version(smb2, SMB2_VERSION_ANY);
smb2_set_timeout(smb2, 30);
if (smb2_connect_share(smb2, smb_url->server, smb_url->share, user.c_str()) < 0)
{
sprintf(response, "%s", smb2_get_error(smb2));
return 0;
}
smb2_destroy_url(smb_url);
connected = true;
return 1;
}
/*
* SmbLastResponse - return a pointer to the last response received
*/
const char *SmbClient::LastResponse()
{
return (const char *)response;
}
/*
* SmbQuit - disconnect from remote
*
* return 1 if successful, 0 otherwise
*/
int SmbClient::Quit()
{
smb2_destroy_context(smb2);
smb2 = NULL;
connected = false;
return 1;
}
/*
* SmbGet - issue a GET command and write received data to output
*
* return 1 if successful, 0 otherwise
*/
int SmbClient::Get(const std::string &outputfile, const std::string &ppath, uint64_t offset)
{
std::string path = std::string(ppath);
path = Util::Trim(path, "/");
struct smb2fh* in = smb2_open(smb2, path.c_str(), O_RDONLY);
if (in == NULL)
{
sprintf(response, "%s", smb2_get_error(smb2));
return 0;
}
FILE* out = NULL;
if (offset > 0)
{
out = FS::Append(outputfile);
}
else
{
out = FS::Create(outputfile);
}
if (out == NULL)
{
// sprintf(response, "%s", lang_strings[STR_FAILED]);
return 0;
}
uint8_t *buff = (uint8_t*)malloc(max_read_size);
int count = 0;
*g_bytes_transfered = offset;
if (offset > 0)
{
smb2_lseek(smb2, in, offset, SEEK_SET, NULL);
}
while ((count = smb2_read(smb2, in, buff, max_read_size)) > 0)
{
if (count < 0)
{
sprintf(response, "%s", smb2_get_error(smb2));
FS::Close(out);
smb2_close(smb2, in);
free((void*)buff);
return 0;
}
FS::Write(out, buff, count);
*g_bytes_transfered += count;
sceSystemServicePowerTick();
}
FS::Close(out);
smb2_close(smb2, in);
free((void*)buff);
return 1;
}
int SmbClient::GetRange(const std::string &ppath, DataSink &sink, uint64_t size, uint64_t offset)
{
std::string path = std::string(ppath);
path = Util::Trim(path, "/");
struct smb2fh *in = smb2_open(smb2, path.c_str(), O_RDONLY);
if (in == NULL)
{
return 0;
}
int ret = this->GetRange((void *)in, sink, size, offset);
smb2_close(smb2, in);
return ret;
}
int SmbClient::GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset)
{
struct smb2fh *in = (struct smb2fh *)fp;
smb2_lseek(smb2, in, offset, SEEK_SET, NULL);
uint8_t *buff = (uint8_t *)malloc(max_read_size);
int count = 0;
size_t bytes_remaining = size;
do
{
size_t bytes_to_read = std::min<size_t>(max_read_size, bytes_remaining);
count = smb2_read(smb2, in, buff, bytes_to_read);
if (count > 0)
{
bytes_remaining -= count;
bool ok = sink.write((char *)buff, count);
if (!ok)
{
free((uint8_t *)buff);
return 0;
}
}
else
{
break;
}
} while (1);
free((char *)buff);
return 1;
}
+35
View File
@@ -0,0 +1,35 @@
#ifndef SMBCLIENT_H
#define SMBCLIENT_H
#include <sys/socket.h>
#include <arpa/inet.h>
#include <time.h>
#include <string>
#include <vector>
#include <smb2/smb2.h>
#include <smb2/libsmb2.h>
#include "clients/remote_client.h"
#define SMB_CLIENT_MAX_FILENAME_LEN 256
class SmbClient : public RemoteClient
{
public:
SmbClient();
~SmbClient();
int Connect(const std::string &url, const std::string &user, const std::string &pass);
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
int GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset);
const char *LastResponse();
int Quit();
private:
struct smb2_context *smb2;
char response[1024];
bool connected = false;
uint32_t max_read_size = 1048576;
uint32_t max_write_size = 1048576;
};
#endif
+19
View File
@@ -0,0 +1,19 @@
#include <fstream>
#include <regex>
#include <sys/time.h>
#include "clients/remote_client.h"
#include "clients/webdav.h"
#include "util.h"
std::string WebDAVClient::GetHttpUrl(std::string url)
{
std::string http_url = std::regex_replace(url, std::regex("webdav://"), "http://");
http_url = std::regex_replace(http_url, std::regex("webdavs://"), "https://");
return http_url;
}
int WebDAVClient::Connect(const std::string &host, const std::string &user, const std::string &pass)
{
std::string url = GetHttpUrl(host);
return BaseClient::Connect(url, user, pass);
}
+18
View File
@@ -0,0 +1,18 @@
#ifndef WEBDAV_H
#define WEBDAV_H
#include <string>
#include <vector>
#include "clients/baseclient.h"
#include "clients/remote_client.h"
class WebDAVClient : public BaseClient
{
public:
int Connect(const std::string &url, const std::string &user, const std::string &pass);
private:
static std::string GetHttpUrl(std::string url);
};
#endif
+257
View File
@@ -0,0 +1,257 @@
// #include <orbis/UserService.h>
// #include <orbis/Net.h>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <regex>
//#include <shared_mutex>
#include <stdlib.h>
#include <json-c/json.h>
#include "server/http_server.h"
#include "config.h"
#include "fs.h"
#include "crypt.h"
#include "base64.h"
#include "util.h"
static std::map<std::string, PackageInstallData> pkg_download_history;
std::vector<BgDownloadData> bg_download_list;
unsigned char cipher_key[32] = {'s', '5', 'v', '8', 'y', '/', 'B', '?', 'E', '(', 'H', '+', 'M', 'b', 'Q', 'e', 'T', 'h', 'W', 'm', 'Z', 'q', '4', 't', '7', 'w', '9', 'z', '$', 'C', '&', 'F'};
unsigned char cipher_iv[16] = {'Y', 'p', '3', 's', '6', 'v', '9', 'y', '$', 'B', '&', 'E', ')', 'H', '@', 'M'};
//std::shared_mutex pkg_mutex_;
//std::shared_mutex download_mutex_;
uint64_t *g_bytes_transfered;
namespace CONFIG
{
int Encrypt(const std::string &text, std::string &encrypt_text)
{
unsigned char tmp_encrypt_text[text.length() * 2];
int encrypt_text_len;
memset(tmp_encrypt_text, 0, sizeof(tmp_encrypt_text));
int ret = openssl_encrypt((unsigned char *)text.c_str(), text.length(), cipher_key, cipher_iv, tmp_encrypt_text, &encrypt_text_len);
if (ret == 0)
return 0;
return Base64::Encode(std::string((const char *)tmp_encrypt_text, encrypt_text_len), encrypt_text);
}
int Decrypt(const std::string &text, std::string &decrypt_text)
{
std::string tmp_decode_text;
int ret = Base64::Decode(text, tmp_decode_text);
if (ret == 0)
return 0;
unsigned char tmp_decrypt_text[tmp_decode_text.length() * 2];
int decrypt_text_len;
memset(tmp_decrypt_text, 0, sizeof(tmp_decrypt_text));
ret = openssl_decrypt((unsigned char *)tmp_decode_text.c_str(), tmp_decode_text.length(), cipher_key, cipher_iv, tmp_decrypt_text, &decrypt_text_len);
if (ret == 0)
return 0;
decrypt_text.clear();
decrypt_text.append(std::string((const char *)tmp_decrypt_text, decrypt_text_len));
return 1;
}
PackageInstallData* GetPackageInstallHostData(const std::string &hash)
{
if (pkg_download_history.find(hash) != pkg_download_history.end())
return &pkg_download_history[hash];
return nullptr;
}
void AddPackageInstallHostData(const std::string &hash, PackageInstallData pkg_data)
{
//std::unique_lock<std::shared_mutex> lock(pkg_mutex_);
std::pair<std::string, PackageInstallData> pair = std::make_pair(hash, pkg_data);
pkg_download_history.erase(hash);
pkg_download_history.insert(pair);
}
void RemovePackageInstallHostData(const std::string &hash)
{
//std::unique_lock<std::shared_mutex> lock(pkg_mutex_);
pkg_download_history.erase(hash);
}
void LoadPackageInstallHostData()
{
if (FS::FileExists(PKG_INSTALL_HISTORY_PATH))
{
json_object *jobj = json_object_from_file(PKG_INSTALL_HISTORY_PATH);
struct array_list *history_list = json_object_get_array(jobj);
for (size_t history_idx = 0; history_idx < history_list->length; ++history_idx)
{
PackageInstallData history_item;
json_object *history_item_obj = (json_object *)array_list_get_idx(history_list, history_idx);
std::string hash = std::string(json_object_get_string(json_object_object_get(history_item_obj, "hash")));
history_item.host_info.url = std::string(json_object_get_string(json_object_object_get(history_item_obj, "url")));
history_item.path = std::string(json_object_get_string(json_object_object_get(history_item_obj, "path")));
history_item.host_info.username = std::string(json_object_get_string(json_object_object_get(history_item_obj, "username")));
std::string encrypted_password = std::string(json_object_get_string(json_object_object_get(history_item_obj, "password")));
history_item.host_info.type = json_object_get_int(json_object_object_get(history_item_obj, "type"));
history_item.timestamp = json_object_get_uint64(json_object_object_get(history_item_obj, "timestamp"));
history_item.client = nullptr;
if (history_item.host_info.type == CLIENT_TYPE_HTTP_SERVER)
{
history_item.host_info.http_server_type = std::string(json_object_get_string(json_object_object_get(history_item_obj, "http_server_type")));
}
int ret = Decrypt(encrypted_password, history_item.host_info.password);
if (ret == 0)
{
history_item.host_info.password = encrypted_password;
}
AddPackageInstallHostData(hash, history_item);
}
json_object_put(jobj);
}
}
void SavePackageInstallHostData()
{
//std::unique_lock<std::shared_mutex> lock(pkg_mutex_);
if (!FS::FolderExists(DATA_PATH))
{
FS::MkDirs(DATA_PATH);
}
json_object *history_list = json_object_new_array();
uint64_t current_time = Util::GetTick();
for (auto it = pkg_download_history.begin(); it != pkg_download_history.end(); ++it)
{
if (current_time - it->second.timestamp < MAX_PKG_HISTORY_RETENTION)
{
json_object *history_item_obj = json_object_new_object();
json_object_object_add(history_item_obj, "hash", json_object_new_string(it->first.c_str()));
json_object_object_add(history_item_obj, "url", json_object_new_string(it->second.host_info.url.c_str()));
json_object_object_add(history_item_obj, "path", json_object_new_string(it->second.path.c_str()));
json_object_object_add(history_item_obj, "username", json_object_new_string(it->second.host_info.username.c_str()));
json_object_object_add(history_item_obj, "type", json_object_new_int(it->second.host_info.type));
json_object_object_add(history_item_obj, "timestamp", json_object_new_uint64(it->second.timestamp));
if (it->second.host_info.type == CLIENT_TYPE_HTTP_SERVER)
{
json_object_object_add(history_item_obj, "http_server_type", json_object_new_string(it->second.host_info.http_server_type.c_str()));
}
std::string encrypted_password;
if (!it->second.host_info.password.empty())
{
Encrypt(it->second.host_info.password, encrypted_password);
}
json_object_object_add(history_item_obj, "password", json_object_new_string(encrypted_password.c_str()));
json_object_array_add(history_list, history_item_obj);
}
}
json_object_to_file(PKG_INSTALL_HISTORY_PATH, history_list);
json_object_put(history_list);
}
void AddBgDownloadData(BgDownloadData pkg_data)
{
//std::unique_lock<std::shared_mutex> lock(download_mutex_);
bg_download_list.push_back(pkg_data);
}
void LoadBgDownloadData()
{
if (FS::FileExists(BG_DOWNLOAD_HISTORY_PATH))
{
json_object *jobj = json_object_from_file(BG_DOWNLOAD_HISTORY_PATH);
struct array_list *history_list = json_object_get_array(jobj);
for (size_t history_idx = 0; history_idx < history_list->length; ++history_idx)
{
BgDownloadData history_item;
json_object *history_item_obj = (json_object *)array_list_get_idx(history_list, history_idx);
history_item.host_info.type = json_object_get_int(json_object_object_get(history_item_obj, "type"));
history_item.host_info.url = std::string(json_object_get_string(json_object_object_get(history_item_obj, "url")));
history_item.host_info.username = std::string(json_object_get_string(json_object_object_get(history_item_obj, "username")));
std::string encrypted_password = std::string(json_object_get_string(json_object_object_get(history_item_obj, "password")));
if (history_item.host_info.type == CLIENT_TYPE_HTTP_SERVER)
{
history_item.host_info.http_server_type = std::string(json_object_get_string(json_object_object_get(history_item_obj, "http_server_type")));
}
int ret = Decrypt(encrypted_password, history_item.host_info.password);
if (ret == 0)
{
history_item.host_info.password = encrypted_password;
}
history_item.src_path = std::string(json_object_get_string(json_object_object_get(history_item_obj, "src_path")));
history_item.dest_path = std::string(json_object_get_string(json_object_object_get(history_item_obj, "dest_path")));
history_item.file_size = json_object_get_uint64(json_object_object_get(history_item_obj, "file_size"));
history_item.bytes_transfered = json_object_get_uint64(json_object_object_get(history_item_obj, "bytes_transfered"));
history_item.state = static_cast<DownloadState>(json_object_get_int(json_object_object_get(history_item_obj, "state")));
history_item.id = json_object_get_uint64(json_object_object_get(history_item_obj, "id"));
history_item.timestamp = json_object_get_uint64(json_object_object_get(history_item_obj, "timestamp"));
AddBgDownloadData(history_item);
}
json_object_put(jobj);
}
}
void SaveBgDownloadData()
{
//std::unique_lock<std::shared_mutex> lock(download_mutex_);
if (!FS::FolderExists(DATA_PATH))
{
FS::MkDirs(DATA_PATH);
}
json_object *history_list = json_object_new_array();
uint64_t current_time = Util::GetTick();
for (auto it = bg_download_list.begin(); it != bg_download_list.end(); ++it)
{
if (current_time - it->timestamp < MAX_PKG_HISTORY_RETENTION)
{
json_object *history_item_obj = json_object_new_object();
json_object_object_add(history_item_obj, "type", json_object_new_int(it->host_info.type));
json_object_object_add(history_item_obj, "url", json_object_new_string(it->host_info.url.c_str()));
if (it->host_info.type == CLIENT_TYPE_HTTP_SERVER)
{
json_object_object_add(history_item_obj, "http_server_type", json_object_new_string(it->host_info.http_server_type.c_str()));
}
std::string encrypted_password;
if (!it->host_info.password.empty())
{
Encrypt(it->host_info.password, encrypted_password);
}
json_object_object_add(history_item_obj, "username", json_object_new_string(it->host_info.username.c_str()));
json_object_object_add(history_item_obj, "password", json_object_new_string(encrypted_password.c_str()));
json_object_object_add(history_item_obj, "src_path", json_object_new_string(it->src_path.c_str()));
json_object_object_add(history_item_obj, "dest_path", json_object_new_string(it->dest_path.c_str()));
json_object_object_add(history_item_obj, "file_size", json_object_new_uint64(it->file_size));
json_object_object_add(history_item_obj, "bytes_transfered", json_object_new_uint64(it->bytes_transfered));
json_object_object_add(history_item_obj, "state", json_object_new_int(it->state));
json_object_object_add(history_item_obj, "id", json_object_new_uint64(it->id));
json_object_object_add(history_item_obj, "timestamp", json_object_new_uint64(it->timestamp));
json_object_array_add(history_list, history_item_obj);
}
}
json_object_to_file(BG_DOWNLOAD_HISTORY_PATH, history_list);
json_object_put(history_list);
}
}
+76
View File
@@ -0,0 +1,76 @@
#ifndef EZ_CONFIG_H
#define EZ_CONFIG_H
#include <string>
#include <vector>
#include <string>
#include <algorithm>
#include <map>
#include <set>
#include "clients/remote_client.h"
#define APP_ID "ezremote-client"
#define DATA_PATH "/data/homebrew/" APP_ID
#define PKG_INSTALL_HISTORY_PATH DATA_PATH "/pkg_install_history.json"
#define BG_DOWNLOAD_HISTORY_PATH DATA_PATH "/bg_download_history.json"
#define DEBUG_SERVER_LOG_PATH DATA_PATH "/ezremote_server.log"
#define NOTIFY_ICON_FILE "/user" DATA_PATH "/sce_sys/icon0.png"
#define CLIENT_ELF_PATH DATA_PATH "/ezremote_client.elf"
#define HTTP_SERVER_APACHE "Apache"
#define HTTP_SERVER_MS_IIS "Microsoft IIS"
#define HTTP_SERVER_NGINX "Nginx"
#define HTTP_SERVER_NPX_SERVE "Serve"
#define HTTP_SERVER_RCLONE "RClone"
#define HTTP_SERVER_ARCHIVEORG "Archive.org"
#define HTTP_SERVER_MYRIENT "Myrient"
#define HTTP_SERVER_GITHUB "Github"
#define MAX_PKG_HISTORY_RETENTION 1209600000000L
enum DownloadState { STATE_PENDING, STATE_DOWNLOADING, STATE_RESUMED, STATE_FAILED, STATE_SUCCESS };
struct HostInfo
{
int type;
std::string url;
std::string http_server_type;
std::string username;
std::string password;
};
struct PackageInstallData
{
HostInfo host_info;
RemoteClient *client;
std::string path;
uint64_t timestamp;
};
struct BgDownloadData {
HostInfo host_info;
std::string src_path;
std::string dest_path;
uint64_t bytes_transfered;
uint64_t file_size;
DownloadState state;
uint64_t id;
uint64_t timestamp;
};
extern uint64_t *g_bytes_transfered;
extern std::vector<BgDownloadData> bg_download_list;
namespace CONFIG
{
PackageInstallData* GetPackageInstallHostData(const std::string &hash);
void AddPackageInstallHostData(const std::string &hash, PackageInstallData pkg_data);
void RemovePackageInstallHostData(const std::string &hash);
void LoadPackageInstallHostData();
void SavePackageInstallHostData();
void AddBgDownloadData(BgDownloadData bg_download_data);
void LoadBgDownloadData();
void SaveBgDownloadData();
}
#endif
+87
View File
@@ -0,0 +1,87 @@
#include "crypt.h"
int openssl_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
unsigned char *iv, unsigned char *ciphertext, int *ciphertext_len)
{
EVP_CIPHER_CTX *ctx;
int len;
/* Create and initialise the context */
if (!(ctx = EVP_CIPHER_CTX_new()))
return 0;
/*
* Initialise the encryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
* In this example we are using 256 bit AES (i.e. a 256 bit key). The
* IV size for *most* modes is the same as the block size. For AES this
* is 128 bits
*/
if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
return 0;
/*
* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if (1 != EVP_CipherUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
return 0;
*ciphertext_len = len;
/*
* Finalise the encryption. Further ciphertext bytes may be written at
* this stage.
*/
if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
return 0;
*ciphertext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return 1;
}
int openssl_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
unsigned char *iv, unsigned char *plaintext, int *plaintext_len)
{
EVP_CIPHER_CTX *ctx;
int len;
/* Create and initialise the context */
if (!(ctx = EVP_CIPHER_CTX_new()))
return 0;
/*
* Initialise the decryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
* In this example we are using 256 bit AES (i.e. a 256 bit key). The
* IV size for *most* modes is the same as the block size. For AES this
* is 128 bits
*/
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
return 0;
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary.
*/
if (1 != EVP_CipherUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
return 0;
*plaintext_len = len;
/*
* Finalise the decryption. Further plaintext bytes may be written at
* this stage.
*/
if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
return 0;
*plaintext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return 1;
}
+18
View File
@@ -0,0 +1,18 @@
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#ifdef __cplusplus
extern "C"
{
#endif
int openssl_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
unsigned char *iv, unsigned char *ciphertext, int *ciphertext_len);
int openssl_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
unsigned char *iv, unsigned char *plaintext, int *plaintext_len);
#ifdef __cplusplus
}
#endif
+442
View File
@@ -0,0 +1,442 @@
/*
*
* DBGLOGGER - debug logger library / (c) 2019 El Bucanero <www.bucanero.com.ar>
*
* Small library for network and local file debug logging in PSL1GHT/Open Orbis SDKs.
*
*/
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <time.h>
#define netConnect connect
#define netClose close
#define netSend send
#define netSocket socket
#define netInitialize(...)
#define netDeinitialize(...)
#include "dbglogger.h"
typedef enum {
ENCODE_BASE64,
ENCODE_UUENCODE
} B64ENC_MODES;
static int loggerMode = NO_LOGGER;
static int socketFD;
static char logFile[256];
#define UDP_INI_STR "udp"
#define TCP_INI_STR "tcp"
#define FILE_INI_STR "file"
#define TTY_INI_STR "tty"
#define DEBUG_PORT 18194
#define BASE64_LENGTH(X) (4 * ((X + 2) / 3))
#define B64_SRC_BUF_SIZE 45 // This *MUST* be a multiple of 3
#define B64_DST_BUF_SIZE BASE64_LENGTH(B64_SRC_BUF_SIZE)
static const char encode_table[2][65] = {
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
"`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"};
/*
* Copyright (C) 2000 by Glenn McGrath
*
* based on the function base64_encode from http.c in wget v1.6
* Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
*
* Encode the string S of length LENGTH to base64 format and place it
* to STORE. STORE will be 0-terminated, and must point to a writable
* buffer of at least 1+BASE64_LENGTH(length) bytes.
* where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3))
*/
static void uuencode(const unsigned char *s, char *store, const int length, const char *tbl)
{
int i;
unsigned char *p = (unsigned char *)store;
/* Transform the 3x8 bits to 4x6 bits, as required by base64. */
for (i = 0; i < length; i += 3) {
*p++ = tbl[s[0] >> 2];
*p++ = tbl[((s[0] & 0x03) << 4) + (s[1] >> 4)];
*p++ = tbl[((s[1] & 0x0f) << 2) + (s[2] >> 6)];
*p++ = tbl[s[2] & 0x3f];
s += 3;
}
/* Pad the result if necessary... */
if (i == length + 1) {
*(p - 1) = tbl[64];
}
else if (i == length + 2) {
*(p - 1) = *(p - 2) = tbl[64];
}
/* ...and zero-terminate it. */
*p = '\0';
}
static int dbglogger_base64(const char *filename, const unsigned int encode)
{
FILE *src_stream;
size_t size;
unsigned char *src_buf;
char *dst_buf;
src_stream = fopen(filename, "rb");
if (!src_stream) {
return(0);
}
src_buf = malloc(B64_SRC_BUF_SIZE + 1);
dst_buf = malloc(B64_DST_BUF_SIZE + 1);
dbglogger_printf("begin%s %o %s", encode == ENCODE_UUENCODE ? "" : "-base64", 0644, strrchr(filename, '/')+1);
while ((size = fread(src_buf, 1, B64_SRC_BUF_SIZE, src_stream)) > 0) {
if (size != B64_SRC_BUF_SIZE) {
/* pad with 0s so we can just encode extra bits */
memset(&src_buf[size], 0, B64_SRC_BUF_SIZE - size);
}
/* Encode the buffer we just read in */
uuencode(src_buf, dst_buf, size, encode_table[encode]);
switch (encode) {
case ENCODE_BASE64:
dbglogger_printf("\n%s", dst_buf);
break;
case ENCODE_UUENCODE:
dbglogger_printf("\n%c%s", encode_table[encode][size], dst_buf);
break;
}
}
dbglogger_printf(encode == ENCODE_UUENCODE ? "\n`\nend\n" : "\n====\n");
free(src_buf);
free(dst_buf);
fclose(src_stream);
return(1);
}
int dbglogger_b64encode(const char *filename)
{
return dbglogger_base64(filename, ENCODE_BASE64);
}
char* dbg_base64_encode(const unsigned char *data, int data_len)
{
char* out = malloc(BASE64_LENGTH(data_len) + 1);
if (!out)
return NULL;
uuencode(data, out, data_len, encode_table[ENCODE_BASE64]);
return (out);
}
/*
* base64_decode - Base64 decode
* @src: Data to be decoded
* @out_len: Pointer to output length variable
* Returns: Allocated buffer of out_len bytes of decoded data, or NULL on failure
*
* Caller is responsible for freeing the returned buffer.
*/
unsigned char * dbg_base64_decode(const char *src, size_t *out_len)
{
unsigned char dtable[256], *out, *pos, block[4], tmp;
size_t i, count, len = strlen(src);
int pad = 0;
memset(dtable, 0x80, 256);
for (i = 0; i < sizeof(encode_table[ENCODE_BASE64]) - 1; i++)
dtable[(unsigned char)encode_table[ENCODE_BASE64][i]] = (unsigned char) i;
dtable['='] = 0;
count = 0;
for (i = 0; i < len; i++) {
if (dtable[(unsigned char)src[i]] != 0x80)
count++;
}
if (count == 0 || count % 4)
return NULL;
pos = out = malloc(count / 4 * 3);
if (out == NULL)
return NULL;
count = 0;
for (i = 0; i < len; i++) {
tmp = dtable[(unsigned char)src[i]];
if (tmp == 0x80)
continue;
if (src[i] == '=')
pad++;
block[count] = tmp;
count++;
if (count == 4) {
*pos++ = (block[0] << 2) | (block[1] >> 4);
*pos++ = (block[1] << 4) | (block[2] >> 2);
*pos++ = (block[2] << 6) | block[3];
count = 0;
if (pad) {
if (pad == 1)
pos--;
else if (pad == 2)
pos -= 2;
else {
// Invalid padding
free(out);
return NULL;
}
break;
}
}
}
*out_len = pos - out;
return out;
}
#ifdef __PPU__
// check if we receive a connection and kill the process
static void debug_netkill_thread(void *port)
{
struct sockaddr_in sa;
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(strtoul(port, NULL, 0));
sa.sin_addr.s_addr = htonl(INADDR_ANY);
int list_s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if ((bind(list_s, (struct sockaddr *)&sa, sizeof(sa)) == -1) || (listen(list_s, 4) == -1))
{
return;
}
while(accept(list_s, NULL, NULL) <= 0)
{
usleep(1000*1000);
}
shutdown(list_s, SHUT_RDWR);
dbglogger_stop();
sysProcessExit(1);
}
// check if the file exists and kill the process
static void debug_kill_thread(void* path)
{
struct stat sb;
while ((stat((char*) path, &sb) != 0) || !S_ISREG(sb.st_mode))
{
usleep(1000*1000);
}
chmod((char*) path, 0777);
sysLv2FsUnlink((char*) path);
dbglogger_stop();
sysProcessExit(1);
}
int dbglogger_failsafe(const char* fpath)
{
sys_ppu_thread_t tid;
return sysThreadCreate(&tid, (fpath[0] == '/' ? debug_kill_thread : debug_netkill_thread), (void*) fpath, 1000, 16*1024, THREAD_JOINABLE, "debug_wait");
}
#endif
static void networkInit(const char* dbglog_ip, const unsigned short dbglog_port) {
struct sockaddr_in stSockAddr;
memset(&stSockAddr, 0, sizeof(stSockAddr));
stSockAddr.sin_family = AF_INET;
stSockAddr.sin_port = htons(dbglog_port);
#ifdef __PS2__
stSockAddr.sin_addr.s_addr = inet_addr(dbglog_ip);
#else
inet_pton(AF_INET, dbglog_ip, &stSockAddr.sin_addr);
#endif
netConnect(socketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr));
}
static int logFileInit(const char* file_path, unsigned short overwrite) {
snprintf(logFile, sizeof(logFile), "%s", file_path);
FILE *fp = fopen(logFile, overwrite ? "w" : "a");
if (fp) {
fclose(fp);
} else {
loggerMode = NO_LOGGER;
}
return(loggerMode);
}
static void fileLog(const char* str) {
FILE *fp = fopen(logFile, "a");
if (fp) {
fputs(str, fp);
fclose(fp);
}
}
void dbglogger_printf(const char* fmt, ...) {
if (loggerMode) {
char buffer[0x800];
va_list arg;
va_start(arg, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, arg);
va_end(arg);
switch (loggerMode) {
case UDP_LOGGER:
case TCP_LOGGER:
netSend(socketFD, buffer, strlen(buffer), 0);
break;
case FILE_LOGGER:
fileLog(buffer);
break;
case TTY_LOGGER:
printf("%s", buffer); // puts always append newline
break;
}
}
}
void dbglogger_log(const char* fmt, ...) {
if (loggerMode) {
char buffer[0x800];
va_list arg;
va_start(arg, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, arg);
va_end(arg);
#ifdef __PSP__
ScePspDateTime t;
sceRtcGetCurrentClockLocalTime(&t);
dbglogger_printf("[%d-%02d-%02d %02d:%02d:%02d] %s\n", t.year, t.month, t.day, t.hour, t.minute, t.second, buffer);
#else
struct tm t = *gmtime(&(time_t){time(NULL)});
dbglogger_printf("[%d-%02d-%02d %02d:%02d:%02d] %s\n", t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, buffer);
#endif
}
}
int dbglogger_init_mode(const unsigned char log_mode, const char* dest, const unsigned short port) {
loggerMode = log_mode;
switch (log_mode) {
case UDP_LOGGER:
netInitialize();
socketFD = netSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
networkInit(dest, port);
dbglogger_log("------ UDP (%s:%d) network debug logger initialized -----", dest, port);
break;
case TCP_LOGGER:
netInitialize();
socketFD = netSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
networkInit(dest, port);
dbglogger_log("------ TCP (%s:%d) network debug logger initialized -----", dest, port);
break;
case FILE_LOGGER:
if (logFileInit(dest, port))
dbglogger_log("----- File (%s) debug logger initialized -----", dest);
break;
case TTY_LOGGER:
dbglogger_log("------ TTY logger initialized ------");
break;
default:
loggerMode = NO_LOGGER;
// Logging disabled
break;
}
return(loggerMode);
}
int dbglogger_init_str(const char* ini_str) {
char str[128];
strcpy(str, ini_str);
char *mode = strtok(str, ":");
char *data = strtok(NULL, ":");
char *tmp = strtok(NULL, ":");
unsigned short port = DEBUG_PORT;
if (tmp)
port = strtoul(tmp, NULL, 0);
if (strcmp(mode, UDP_INI_STR) == 0) {
return dbglogger_init_mode(UDP_LOGGER, data, port);
} else
if (strcmp(mode, TCP_INI_STR) == 0) {
return dbglogger_init_mode(TCP_LOGGER, data, port);
} else
if (strcmp(mode, FILE_INI_STR) == 0) {
return dbglogger_init_mode(FILE_LOGGER, data, 0);
} else
if (strcmp(mode, TTY_INI_STR) == 0) {
return dbglogger_init_mode(TTY_LOGGER, NULL, 0);
}
return(NO_LOGGER);
}
int dbglogger_init_file(const char* ini_file) {
char str[128];
FILE *fp = fopen(ini_file, "r");
if (fp) {
fgets(str, sizeof(str), fp);
fclose(fp);
return(dbglogger_init_str(str));
}
return(NO_LOGGER);
}
int dbglogger_init(void) {
return(dbglogger_init_str(DEFAULT_LOG_INIT));
}
int dbglogger_stop(void) {
switch (loggerMode) {
case UDP_LOGGER:
case TCP_LOGGER:
dbglogger_log("------ network debug logger terminated -----");
netClose(socketFD);
netDeinitialize();
break;
case FILE_LOGGER:
dbglogger_log("------ file debug logger terminated -----");
break;
default:
// Logging disabled
break;
}
loggerMode = NO_LOGGER;
return(loggerMode);
}
+108
View File
@@ -0,0 +1,108 @@
/*
*
* DBGLOGGER - debug logger library / (c) 2019 El Bucanero <www.bucanero.com.ar>
*
By default the logger will send debug messages to UDP multicast address 239.255.0.100:30000.
To receive them you can use socat on your PC:
$ socat udp4-recv:30000,ip-add-membership=239.255.0.100:0.0.0.0 -
TCP/UDP Usage:
1. Set the correct IP/port to your computer (default port 18194)
2. Execute a local tool to listen to the incoming messages (e.g. netcat, socat)
Try any of these commands in your terminal:
UDP
$ nc -l -u 18194
$ socat udp-recv:18194 stdout
TCP
$ nc -l -k 18194
$ socat tcp-listen:18194 stdout
3. Start the app on your console.
*/
#ifndef LIBDEBUGLOG_H
#define LIBDEBUGLOG_H
#ifdef __cplusplus
extern "C" {
#endif
#define DEFAULT_LOG_INIT "udp:239.255.0.100:30000"
// TCP example string "tcp:192.168.1.123:18194"
// File example string "file:/dev_hdd0/temp/app.log"
typedef enum {
NO_LOGGER,
UDP_LOGGER,
TCP_LOGGER,
FILE_LOGGER,
TTY_LOGGER
} LOGGER_MODES;
typedef struct {
char method;
char *resource;
} dWebRequest_t;
typedef struct {
char type[8];
char *data;
int64_t size;
} dWebResponse_t;
/*
int webReq_GetHandler(dWebRequest_t* request, dWebResponse_t* response, void* usr_data);
*/
typedef int (*dWebReqHandler_t)(dWebRequest_t*, dWebResponse_t*, void*);
int dbglogger_init(void);
int dbglogger_init_str(const char* ini_str);
int dbglogger_init_mode(const unsigned char log_mode, const char* dest, const unsigned short port);
int dbglogger_init_file(const char* ini_file);
int dbglogger_stop(void);
// function to print with format string similar to printf
void dbglogger_printf(const char* fmt, ...);
// function that prints "[timestamp] log \n" similar to printf
void dbglogger_log(const char* fmt, ...);
// starts a thread that terminates the process if the file exists
int dbglogger_failsafe(const char* fpath);
// screenshot method
int dbglogger_screenshot(const char* filename, const unsigned char alpha);
// screenshot will be placed in /dev_hdd0/tmp/screenshot_YYYY_MM_DD_HH_MM_SS.bmp
int dbglogger_screenshot_tmp(const unsigned char alpha);
// base64 file encoding method
int dbglogger_b64encode(const char* filename);
// base64 data encoding method
char* dbg_base64_encode(const unsigned char *data, int data_len);
// base64 data decoding method
unsigned char * dbg_base64_decode(const char *src, size_t *out_len);
// web server methods
int dbg_webserver_start(int port, dWebReqHandler_t req, void* usr_data);
void dbg_webserver_stop();
// a simple http server handler that serves the system '/' root folder
int dbg_simpleWebServerHandler(dWebRequest_t* req, dWebResponse_t* res, void* data);
#ifdef __cplusplus
}
#endif
#endif
+481
View File
@@ -0,0 +1,481 @@
#include "fs.h"
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <dirent.h>
#include <sys/time.h>
// #include <filesystem>
#include <stdio.h>
#include <unistd.h>
#include <vector>
#include <sys/stat.h>
#include "util.h"
#if defined(EZREMOTE_ENABLE_UI)
#include "windows.h"
#endif
namespace FS
{
int hasEndSlash(const char *path)
{
return path[strlen(path) - 1] == '/';
}
void MkDirs(const std::string &ppath, bool prev)
{
std::string path = ppath;
if (!prev)
{
path.push_back('/');
}
auto ptr = path.begin();
while (true)
{
ptr = std::find(ptr, path.end(), '/');
if (ptr == path.end())
break;
char last = *ptr;
*ptr = 0;
int err = mkdir(path.c_str(), 0777);
*ptr = last;
++ptr;
}
}
void Rm(const std::string &file)
{
remove(file.c_str());
}
void RmDir(const std::string &path)
{
rmdir(path.c_str());
}
int64_t GetSize(const std::string &path)
{
struct stat file_stat = {0};
int err = stat(path.c_str(), &file_stat);
if (err < 0)
{
return -1;
}
return file_stat.st_size;
}
bool FileExists(const std::string &path)
{
struct stat file_stat = {0};
return (stat(path.c_str(), std::addressof(file_stat)) == 0 && S_ISREG(file_stat.st_mode));
}
bool FolderExists(const std::string &path)
{
struct stat dir_stat = {0};
return (stat(path.c_str(), &dir_stat) == 0);
}
int IsFolder(const std::string &path)
{
struct stat dir_stat = {0};
if (stat(path.c_str(), &dir_stat) != 0)
return -1;
if (S_ISDIR(dir_stat.st_mode))
return 1;
return 0;
}
void Rename(const std::string &from, const std::string &to)
{
int res = rename(from.c_str(), to.c_str());
}
FILE *Create(const std::string &path)
{
FILE *fd = fopen(path.c_str(), "w");
return fd;
}
FILE *OpenRW(const std::string &path)
{
FILE *fd = fopen(path.c_str(), "w+");
return fd;
}
FILE *OpenRead(const std::string &path)
{
FILE *fd = fopen(path.c_str(), "rb");
return fd;
}
FILE *Append(const std::string &path)
{
FILE *fd = fopen(path.c_str(), "ab");
return fd;
}
int64_t Seek(FILE *f, uint64_t offset)
{
auto const pos = fseek(f, offset, SEEK_SET);
return pos;
}
int Read(FILE *f, void *buffer, uint32_t size)
{
const auto read = fread(buffer, 1, size, f);
return read;
}
int Write(FILE *f, const void *buffer, uint32_t size)
{
int write = fwrite(buffer, 1, size, f);
return write;
}
void Close(FILE *fd)
{
int err = fclose(fd);
}
std::vector<char> Load(const std::string &path)
{
FILE *fd = fopen(path.c_str(), "rb");
if (fd == nullptr)
return std::vector<char>(0);
const auto size = GetSize(path);
std::vector<char> data(size);
const auto read = fread(data.data(), 1, data.size(), fd);
fclose(fd);
if (read < 0)
return std::vector<char>(0);
data.resize(read+1);
data[data.size()-1]=0;
return data;
}
bool LoadText(std::vector<std::string> *lines, const std::string &path)
{
FILE *fd = fopen(path.c_str(), "rb");
if (fd == nullptr)
return false;
lines->clear();
char buffer[1024];
short bytes_read;
std::vector<char> line = std::vector<char>(0);
do
{
bytes_read = fread(buffer, sizeof(char), 1024, fd);
if (bytes_read < 0)
{
fclose(fd);
return false;
}
for (short i = 0; i < bytes_read; i++)
{
if (buffer[i] != '\r' && buffer[i] != '\n')
{
line.push_back(buffer[i]);
}
else
{
lines->push_back(std::string(line.data(), line.size()));
line = std::vector<char>(0);
if (buffer[i] == '\r' && buffer[i+1] == '\n')
i++;
}
}
} while (bytes_read == 1024);
if (line.size()>0)
lines->push_back(std::string(line.data(), line.size()));
fclose(fd);
if (lines->size() == 0)
lines->push_back("");
return true;
}
bool SaveText(std::vector<std::string> *lines, const std::string &path)
{
FILE *fd = OpenRW(path);
if (fd == nullptr)
return false;
char nl[1] = {'\n'};
for (int i=0; i < lines->size(); i++)
{
Write(fd, lines->at(i).c_str(), lines->at(i).length());
Write(fd, nl, 1);
}
fclose(fd);
return true;
}
bool Save(const std::string &path, const void *data, uint32_t size)
{
FILE *fd = fopen(path.c_str(), "w+");
if (fd == nullptr)
return false;
const char *data8 = static_cast<const char *>(data);
while (size != 0)
{
int written = fwrite(data8, 1, size, fd);
fclose(fd);
if (written <= 0)
return false;
data8 += written;
size -= written;
}
return true;
}
std::vector<std::string> ListFiles(const std::string &path)
{
DIR *fd = opendir(path.c_str());
if (fd == NULL)
return std::vector<std::string>(0);
std::vector<std::string> out;
while (true)
{
struct dirent *dirent;
dirent = readdir(fd);
if (dirent == NULL)
{
closedir(fd);
return out;
}
if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
{
continue;
}
if (dirent->d_type & DT_DIR)
{
std::vector<std::string> files = FS::ListFiles(path + "/" + dirent->d_name);
for (std::vector<std::string>::iterator it = files.begin(); it != files.end();)
{
out.push_back(std::string(dirent->d_name) + "/" + *it);
++it;
}
}
else
{
out.push_back(dirent->d_name);
}
}
closedir(fd);
return out;
}
int RmRecursive(const std::string &path)
{
#if defined(EZREMOTE_ENABLE_UI)
if (stop_activity)
return 1;
#else
bool stop_activity = false;
#endif
DIR *dfd = opendir(path.c_str());
if (dfd != NULL)
{
struct dirent *dir = NULL;
do
{
dir = readdir(dfd);
if (dir == NULL || strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
{
continue;
}
char new_path[512];
snprintf(new_path, 512, "%s%s%s", path.c_str(), hasEndSlash(path.c_str()) ? "" : "/", dir->d_name);
if (dir->d_type & DT_DIR)
{
int ret = RmRecursive(new_path);
if (ret <= 0)
{
#if defined(EZREMOTE_ENABLE_UI)
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_DIR_MSG], new_path);
#endif
closedir(dfd);
return ret;
}
}
else
{
#if defined(EZREMOTE_ENABLE_UI)
snprintf(activity_message, 1024, "%s %s", lang_strings[STR_DELETING], new_path);
#endif
int ret = remove(new_path);
if (ret < 0)
{
#if defined(EZREMOTE_ENABLE_UI)
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_FILE_MSG], new_path);
#endif
closedir(dfd);
return ret;
}
}
} while (dir != NULL && !stop_activity);
closedir(dfd);
if (stop_activity)
return 0;
int ret = rmdir(path.c_str());
if (ret < 0)
{
#if defined(EZREMOTE_ENABLE_UI)
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_DIR_MSG], path.c_str());
#endif
return ret;
}
#if defined(EZREMOTE_ENABLE_UI)
snprintf(activity_message, 1024, "%s %s", lang_strings[STR_DELETED], path.c_str());
#endif
}
else
{
int ret = remove(path.c_str());
if (ret < 0)
{
#if defined(EZREMOTE_ENABLE_UI)
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_FILE_MSG], path.c_str());
#endif
return ret;
}
#if defined(EZREMOTE_ENABLE_UI)
snprintf(activity_message, 1024, "%s %s", lang_strings[STR_DELETED], path.c_str());
#endif
}
return 1;
}
std::string GetPath(const std::string &ppath1, const std::string &ppath2)
{
std::string path1 = ppath1;
std::string path2 = ppath2;
path2 = Util::Rtrim(Util::Trim(path2, " "), "/");
return path1 + "/" + path2;
}
int Head(const std::string &path, void *buffer, uint16_t len)
{
FILE *file = OpenRead(path);
if (file == nullptr)
return 0;
int ret = Read(file, buffer, len);
if (ret != len)
{
Close(file);
return 0;
}
Close(file);
return 1;
}
bool Copy(const std::string &from, const std::string &to)
{
#if !defined(EZREMOTE_ENABLE_UI)
uint64_t bytes_to_download;
uint64_t bytes_transfered;
#endif
MkDirs(to, true);
if (from.compare(to) == 0)
return true;
FILE *src = fopen(from.c_str(), "rb");
if (!src)
{
return false;
}
struct stat file_stat = {0};
if (stat(from.c_str(), &file_stat) != 0)
{
return false;
}
bytes_to_download = file_stat.st_size;
FILE *dest = fopen(to.c_str(), "wb");
if (!dest)
{
fclose(src);
return false;
}
size_t bytes_read = 0;
bytes_transfered = 0;
#if defined(EZREMOTE_ENABLE_UI)
prev_tick = Util::GetTick();
#endif
const size_t buf_size = 0x10000;
unsigned char *buf = new unsigned char[buf_size];
do
{
bytes_read = fread(buf, sizeof(unsigned char), buf_size, src);
if (bytes_read < 0)
{
delete[] buf;
fclose(src);
fclose(dest);
return false;
}
size_t bytes_written = fwrite(buf, sizeof(unsigned char), bytes_read, dest);
if (bytes_written != bytes_read)
{
delete[] buf;
fclose(src);
fclose(dest);
return false;
}
bytes_transfered += bytes_read;
} while (bytes_transfered < bytes_to_download);
delete[] buf;
fclose(src);
fclose(dest);
return true;
}
bool Move(const std::string &from, const std::string &to)
{
if (from.compare(to) == 0)
return true;
errno = 0;
int ret = rename(from.c_str(), to.c_str());
if (ret != 0 && (errno == EXDEV || errno == EEXIST))
{
bool res = Copy(from, to);
if (res)
Rm(from);
else
return res;
}
return true;
}
}
+65
View File
@@ -0,0 +1,65 @@
#ifndef LAUNCHER_FS_H
#define LAUNCHER_FS_H
#pragma once
#include <string.h>
#include <string>
#include <vector>
#include <cstdint>
#define MAX_PATH_LENGTH 1024
namespace FS
{
std::string GetPath(const std::string &path1, const std::string &path2);
void MkDirs(const std::string &path, bool prev = false);
void Rm(const std::string &file);
void RmDir(const std::string &path);
int RmRecursive(const std::string &path);
int64_t GetSize(const std::string &path);
bool FileExists(const std::string &path);
bool FolderExists(const std::string &path);
int IsFolder(const std::string &path);
void Rename(const std::string &from, const std::string &to);
bool Copy(const std::string &from, const std::string &to);
bool Move(const std::string &from, const std::string &to);
// creates file (if it exists, truncates size to 0)
FILE *Create(const std::string &path);
// open existing file in read/write, fails if file does not exist
FILE *OpenRW(const std::string &path);
// open existing file in read/write, fails if file does not exist
FILE *OpenRead(const std::string &path);
// open file for writing, next write will append data to end of it
FILE *Append(const std::string &path);
void Close(FILE *f);
int64_t Seek(FILE *f, uint64_t offset);
int Read(FILE *f, void *buffer, uint32_t size);
int Write(FILE *f, const void *buffer, uint32_t size);
std::vector<char> Load(const std::string &path);
bool LoadText(std::vector<std::string> *lines, const std::string &path);
bool SaveText(std::vector<std::string> *lines, const std::string &path);
bool Save(const std::string &path, const void *data, uint32_t size);
std::vector<std::string> ListFiles(const std::string &path);
int hasEndSlash(const char *path);
int Head(const std::string &path, void* buffer, uint16_t len);
}
#endif
+32
View File
@@ -0,0 +1,32 @@
#include <unistd.h>
#include <sys/random.h>
#include <pthread.h>
#include <errno.h>
int getentropy(void *buffer, size_t len)
{
int cs, ret = 0;
char *pos = buffer;
if (len > 256) {
errno = EIO;
return -1;
}
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
while (len) {
ret = getrandom(pos, len, 0);
if (ret < 0) {
if (errno == EINTR) continue;
else break;
}
pos += ret;
len -= ret;
ret = 0;
}
pthread_setcancelstate(cs, 0);
return ret;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+65
View File
@@ -0,0 +1,65 @@
#undef main
#include <string>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <orbis/libkernel.h>
#include <orbis/Sysmodule.h>
#include <orbis/SystemService.h>
#include <orbis/Net.h>
#include "server/http_server.h"
#include "config.h"
#include "util.h"
#include "dbglogger.h"
extern "C"
{
#include "orbis_jbc.h"
}
static void terminate()
{
terminate_jbc();
sceSystemServiceLoadExec("exit", NULL);
}
int main(int argc, char *argv[])
{
dbglogger_init();
dbglogger_log("If you see this you've set up dbglogger correctly.");
if (!initialize_jbc())
{
terminate();
}
atexit(terminate);
if (sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_SYSTEM_SERVICE) < 0) return 0;
if (sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_USER_SERVICE) < 0) return 0;
if (sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_NET) < 0 || sceNetInit() != 0) return 0;
CONFIG::LoadPackageInstallHostData();
CONFIG::LoadBgDownloadData();
if (HttpServer::IsStarted())
{
Util::Notify("ezRemote Server already started");
terminate();
return 0;
}
dbglogger_log(" Registering Daemon...");
sceSystemServiceRegisterDaemon();
HttpServer::StartDownloadThread();
HttpServer::Start();
Util::Notify("ezRemote Server stopped.");
return 0;
}
+122
View File
@@ -0,0 +1,122 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/uio.h>
#include <orbis/libkernel.h>
#include <libjbc.h>
#define SYSCALL(nr, fn) __attribute__((naked)) fn\
{\
asm volatile("mov $" #nr ", %rax\nmov %rcx, %r10\nsyscall\nret");\
}
SYSCALL(22, static int unmount(const char* path, int flags))
SYSCALL(378, static int nmount(struct iovec* iov, unsigned int niov, int flags))
static void build_iovec(struct iovec** iov, int* iovlen, const char* name, const void* val, size_t len) {
int i;
if (*iovlen < 0)
return;
i = *iovlen;
*iov = (struct iovec*)realloc(*iov, sizeof **iov * (i + 2));
if (*iov == NULL) {
*iovlen = -1;
return;
}
(*iov)[i].iov_base = strdup(name);
(*iov)[i].iov_len = strlen(name) + 1;
++i;
(*iov)[i].iov_base = (void*)val;
if (len == (size_t)-1) {
if (val != NULL)
len = strlen((const char*)val) + 1;
else
len = 0;
}
(*iov)[i].iov_len = (int)len;
*iovlen = ++i;
}
int mount_large_fs(const char* device, const char* mountpoint, const char* fstype, const char* mode, unsigned int flags)
{
struct iovec* iov = NULL;
int iovlen = 0;
unmount(mountpoint, 0);
build_iovec(&iov, &iovlen, "fstype", fstype, -1);
build_iovec(&iov, &iovlen, "fspath", mountpoint, -1);
build_iovec(&iov, &iovlen, "from", device, -1);
build_iovec(&iov, &iovlen, "large", "yes", -1);
build_iovec(&iov, &iovlen, "timezone", "static", -1);
build_iovec(&iov, &iovlen, "async", "", -1);
build_iovec(&iov, &iovlen, "ignoreacl", "", -1);
if (mode) {
build_iovec(&iov, &iovlen, "dirmask", mode, -1);
build_iovec(&iov, &iovlen, "mask", mode, -1);
}
return nmount(iov, iovlen, flags);
}
// Variables for (un)jailbreaking
jbc_cred g_Cred;
jbc_cred g_RootCreds;
// Verify jailbreak
static int is_jailbroken()
{
FILE *s_FilePointer = fopen("/user/.jailbreak", "w");
if (!s_FilePointer)
return 0;
fclose(s_FilePointer);
remove("/user/.jailbreak");
return 1;
}
// Jailbreaks creds
static int jailbreak()
{
if (is_jailbroken())
{
return 1;
}
jbc_get_cred(&g_Cred);
g_RootCreds = g_Cred;
jbc_jailbreak_cred(&g_RootCreds);
jbc_set_cred(&g_RootCreds);
return (is_jailbroken());
}
// Initialize jailbreak
int initialize_jbc()
{
// Pop notification depending on jailbreak result
if (!jailbreak())
{
return 0;
}
return 1;
}
// Unload libjbc libraries
void terminate_jbc()
{
if (!is_jailbroken())
return;
// Restores original creds
jbc_set_cred(&g_Cred);
}
+10
View File
@@ -0,0 +1,10 @@
#ifndef __ORBIS_JBC_H__
#define __ORBIS_JBC_H__
#define MNT_UPDATE 0x0000000000010000ULL
int initialize_jbc();
void terminate_jbc();
int mount_large_fs(const char* device, const char* mountpoint, const char* fstype, const char* mode, unsigned int flags);
#endif
+543
View File
@@ -0,0 +1,543 @@
#include <string>
#include <json-c/json.h>
#include "http/httplib.h"
#include "server/http_server.h"
#include "clients/remote_client.h"
#include "clients/archiveorg.h"
#include "clients/baseclient.h"
#include "clients/ftpclient.h"
#include "clients/nfsclient.h"
#include "clients/smbclient.h"
#include "clients/sftpclient.h"
#include "clients/webdav.h"
#include "config.h"
#include "fs.h"
#include "util.h"
#define SUCCESS_MSG "{ \"result\": { \"success\": true, \"error\": null } }"
#define FAILURE_MSG "{ \"result\": { \"success\": false, \"error\": \"%s\" } }"
#define SUCCESS_MSG_LEN 48
#define PKG_INITIAL_REQUEST_SIZE 8388608ul
using namespace httplib;
Server *svr;
int http_server_port = 6701;
static pthread_t bg_download_thread;
static uint64_t g_dl_offset;
namespace HttpServer
{
static int FtpCallback(int64_t xfered, void *arg)
{
return 1;
}
static int DownloadFtpCallback(int64_t xfered, void *arg)
{
*g_bytes_transfered = g_dl_offset + xfered;
return 1;
}
std::string dump_headers(const Headers &headers)
{
std::string s;
char buf[BUFSIZ];
for (auto it = headers.begin(); it != headers.end(); ++it)
{
const auto &x = *it;
snprintf(buf, sizeof(buf), "%s: %s\n", x.first.c_str(), x.second.c_str());
s += buf;
}
return s;
}
std::string log(const Request &req, const Response &res)
{
std::string s;
char buf[BUFSIZ];
s += "================================\n";
snprintf(buf, sizeof(buf), "%s %s %s", req.method.c_str(),
req.version.c_str(), req.path.c_str());
s += buf;
std::string query;
for (auto it = req.params.begin(); it != req.params.end(); ++it)
{
const auto &x = *it;
snprintf(buf, sizeof(buf), "%c%s=%s",
(it == req.params.begin()) ? '?' : '&', x.first.c_str(),
x.second.c_str());
query += buf;
}
snprintf(buf, sizeof(buf), "%s\n", query.c_str());
s += buf;
s += dump_headers(req.headers);
s += "--------------------------------\n";
snprintf(buf, sizeof(buf), "%d %s\n", res.status, res.version.c_str());
s += buf;
s += dump_headers(res.headers);
s += "\n";
if (!res.body.empty())
{
s += res.body;
}
s += "\n";
return s;
}
void failed(Response &res, int status, const std::string &msg)
{
res.status = status;
char response_msg[msg.length() + strlen(FAILURE_MSG) + 2];
snprintf(response_msg, sizeof(response_msg), "{ \"result\": { \"success\": false, \"error\": \"%s\" } }", msg.c_str());
res.set_content(response_msg, strlen(response_msg), "application/json");
return;
}
void bad_request(Response &res, const std::string &msg)
{
failed(res, 200, msg);
return;
}
void success(Response &res)
{
res.status = 200;
res.set_content(SUCCESS_MSG, SUCCESS_MSG_LEN, "application/json");
return;
}
static RemoteClient *GetRemoteClient(HostInfo *host_info)
{
RemoteClient *tmp_client = nullptr;
if (host_info->type == CLIENT_TYPE_HTTP_SERVER)
{
if (host_info->http_server_type.compare(HTTP_SERVER_ARCHIVEORG))
{
tmp_client = new ArchiveOrgClient();
}
else if (host_info->http_server_type.compare(HTTP_SERVER_APACHE))
{
tmp_client = new BaseClient();
}
else if (host_info->http_server_type.compare(HTTP_SERVER_MS_IIS))
{
tmp_client = new BaseClient();
}
else if (host_info->http_server_type.compare(HTTP_SERVER_NGINX))
{
tmp_client = new BaseClient();
}
else if (host_info->http_server_type.compare(HTTP_SERVER_RCLONE))
{
tmp_client = new BaseClient();
}
else if (host_info->http_server_type.compare(HTTP_SERVER_NPX_SERVE))
{
tmp_client = new BaseClient();
}
}
else if (host_info->type == CLIENT_TYPE_WEBDAV)
{
tmp_client = new WebDAVClient();
}
else if (host_info->type == CLIENT_TYPE_FILEHOST)
{
tmp_client = new BaseClient();
}
else if (host_info->type == CLIENT_TYPE_SMB)
{
tmp_client = new SmbClient();
}
else if (host_info->type == CLIENT_TYPE_SFTP)
{
tmp_client = new SFTPClient();
}
else if (host_info->type == CLIENT_TYPE_NFS)
{
tmp_client = new NfsClient();
}
else if (host_info->type == CLIENT_TYPE_FTP)
{
tmp_client = new FtpClient();
FtpClient *ftp_client = (FtpClient*) tmp_client;
ftp_client->SetCallbackXferFunction(FtpCallback);
}
if (tmp_client != nullptr)
tmp_client->Connect(host_info->url, host_info->username, host_info->password);
return tmp_client;
}
static void DeleteRemoteClient(RemoteClient *tmp_client)
{
if (!dynamic_cast<BaseClient*>(tmp_client))
{
tmp_client->Quit();
delete tmp_client;
}
}
void *DownloadFilesThread(void *argp)
{
char temp_file[2049];
uint64_t tmp_file_size;
int ret;
while (true)
{
for (int i=0; i < bg_download_list.size(); i++)
{
if (bg_download_list[i].state == STATE_PENDING)
{
RemoteClient *tmp_client = GetRemoteClient(&(bg_download_list[i].host_info));
g_bytes_transfered = &(bg_download_list[i].bytes_transfered);
if (bg_download_list[i].host_info.type == CLIENT_TYPE_FTP)
{
FtpClient *ftpclient = (FtpClient*)tmp_client;
g_dl_offset = 0;
ftpclient->SetCallbackBytes(1);
ftpclient->SetCallbackXferFunction(DownloadFtpCallback);
}
bg_download_list[i].state = STATE_DOWNLOADING;
CONFIG::SaveBgDownloadData();
snprintf(temp_file, sizeof(temp_file), "%s.tmp", bg_download_list[i].dest_path.c_str());
Util::RichNotify(bg_download_list[i].id, "Started download %s", bg_download_list[i].dest_path.c_str());
ret = tmp_client->Get(temp_file, bg_download_list[i].src_path);
FS::Rename(temp_file, bg_download_list[i].dest_path);
if (ret == 0)
{
bg_download_list[i].state = STATE_FAILED;
Util::RichNotify(bg_download_list[i].id, "Failed to download %s", bg_download_list[i].dest_path.c_str());
}
else
{
Util::RichNotify(bg_download_list[i].id, "Completed download %s", bg_download_list[i].dest_path.c_str());
bg_download_list[i].state = STATE_SUCCESS;
}
CONFIG::SaveBgDownloadData();
DeleteRemoteClient(tmp_client);
}
else if (bg_download_list[i].state == STATE_DOWNLOADING)
{
// Resume interrupted download
RemoteClient *tmp_client = GetRemoteClient(&(bg_download_list[i].host_info));
g_bytes_transfered = &(bg_download_list[i].bytes_transfered);
if (bg_download_list[i].host_info.type == CLIENT_TYPE_FTP)
{
FtpClient *ftpclient = (FtpClient*)tmp_client;
ftpclient->SetCallbackBytes(1);
ftpclient->SetCallbackXferFunction(DownloadFtpCallback);
}
bg_download_list[i].state = STATE_RESUMED;
snprintf(temp_file, sizeof(temp_file), "%s.tmp", bg_download_list[i].dest_path.c_str());
// Check if temp file still exists, if exists then resume download
Util::RichNotify(bg_download_list[i].id, "Resuming download %s", bg_download_list[i].dest_path.c_str());
if (FS::FileExists(temp_file))
{
tmp_file_size = FS::GetSize(temp_file);
g_dl_offset = tmp_file_size;
ret = tmp_client->Get(temp_file, bg_download_list[i].src_path, tmp_file_size);
}
else
{
g_dl_offset = 0;
ret = tmp_client->Get(temp_file, bg_download_list[i].src_path);
}
FS::Rename(temp_file, bg_download_list[i].dest_path);
if (ret == 0)
{
bg_download_list[i].state = STATE_FAILED;
Util::RichNotify(bg_download_list[i].id, "Failed to download %s", bg_download_list[i].dest_path.c_str());
}
else
{
Util::RichNotify(bg_download_list[i].id, "Completed download %s", bg_download_list[i].dest_path.c_str());
bg_download_list[i].state = STATE_SUCCESS;
}
CONFIG::SaveBgDownloadData();
DeleteRemoteClient(tmp_client);
}
}
sleep(1);
}
return nullptr;
}
void *ServerThread(void *argp)
{
svr->Get("/", [&](const Request &req, Response &res)
{ res.set_redirect("/index.html"); });
svr->Post("/store_bg_install_data", [&](const Request &req, Response &res)
{
const char *hash_param;
const char *path_param;
const char *url_param;
const char *username_param;
const char *password_param;
const char *http_server_type_param;
int type_param;
json_object *jobj = json_tokener_parse(req.body.c_str());
if (jobj != nullptr)
{
hash_param = json_object_get_string(json_object_object_get(jobj, "hash"));
url_param = json_object_get_string(json_object_object_get(jobj, "url"));
path_param = json_object_get_string(json_object_object_get(jobj, "path"));
username_param = json_object_get_string(json_object_object_get(jobj, "username"));
password_param = json_object_get_string(json_object_object_get(jobj, "password"));
http_server_type_param = json_object_get_string(json_object_object_get(jobj, "http_server_type"));
type_param = json_object_get_int(json_object_object_get(jobj, "type"));
if (url_param == nullptr || hash_param == nullptr)
{
bad_request(res, "Required url_param or hash parameter missing");
return;
}
PackageInstallData pkg_data;
pkg_data.host_info.url = url_param;
if (username_param != nullptr)
pkg_data.host_info.username = username_param;
if (password_param != nullptr)
pkg_data.host_info.password = password_param;
if (path_param != nullptr)
pkg_data.path = path_param;
if (http_server_type_param != nullptr)
pkg_data.host_info.http_server_type = http_server_type_param;
pkg_data.timestamp = Util::GetTick();
pkg_data.host_info.type = type_param;
pkg_data.client = nullptr;
CONFIG::AddPackageInstallHostData(hash_param, pkg_data);
CONFIG::SavePackageInstallHostData();
}
});
svr->Get("/bg_install/(.*)", [&](const Request &req, Response &res)
{
std::string hash = req.matches[1];
PackageInstallData* pkg_host_data = CONFIG::GetPackageInstallHostData(hash);
RemoteClient *tmp_client;
if (pkg_host_data == nullptr)
{
failed(res, 500, "Cannot resume background install of " + hash + ". Host data not found.");
return;
}
if (pkg_host_data->host_info.type == CLIENT_TYPE_HTTP_SERVER ||
pkg_host_data->host_info.type == CLIENT_TYPE_WEBDAV ||
pkg_host_data->host_info.type == CLIENT_TYPE_FILEHOST)
{
if (pkg_host_data->client == nullptr)
{
pkg_host_data->client = GetRemoteClient(&(pkg_host_data->host_info));
}
else
{
tmp_client = pkg_host_data->client;
}
}
else
{
tmp_client = GetRemoteClient(&(pkg_host_data->host_info));
}
if (tmp_client == nullptr)
{
res.status = 500;
return;
}
std::string path = pkg_host_data->path;
res.status = 206;
size_t range_len = (req.ranges[0].second - req.ranges[0].first) + 1;
std::pair<ssize_t, ssize_t> range = req.ranges[0];
res.set_content_provider(
range_len, "application/octet-stream",
[tmp_client, path, range, range_len](size_t offset, size_t length, DataSink &sink) {
int ret;
ret = tmp_client->GetRange(path, sink, range_len, range.first);
return (ret==1);
},
[tmp_client](bool success) {
DeleteRemoteClient(tmp_client);
});
});
svr->Post("/download_url", [&](const Request &req, Response &res)
{
int type_param;
const char *url_param;
const char *username_param;
const char *password_param;
const char *http_server_type_param;
const char *src_path_param;
const char *dest_path_param;
uint64_t file_size_param;
uint64_t id_param;
json_object *jobj = json_tokener_parse(req.body.c_str());
if (jobj != nullptr)
{
type_param = json_object_get_int(json_object_object_get(jobj, "type"));
url_param = json_object_get_string(json_object_object_get(jobj, "url"));
username_param = json_object_get_string(json_object_object_get(jobj, "username"));
password_param = json_object_get_string(json_object_object_get(jobj, "password"));
http_server_type_param = json_object_get_string(json_object_object_get(jobj, "http_server_type"));
src_path_param = json_object_get_string(json_object_object_get(jobj, "src_path"));
dest_path_param = json_object_get_string(json_object_object_get(jobj, "dest_path"));
file_size_param = json_object_get_uint64(json_object_object_get(jobj, "size"));
id_param = json_object_get_uint64(json_object_object_get(jobj, "id"));
if (url_param == nullptr || src_path_param == nullptr || dest_path_param == nullptr)
{
bad_request(res, "Required parameters are missing");
return;
}
BgDownloadData download_data;
download_data.host_info.type = type_param;
download_data.host_info.url = url_param;
download_data.src_path = src_path_param;
download_data.dest_path = dest_path_param;
download_data.file_size = file_size_param;
download_data.state = STATE_PENDING;
download_data.id = id_param;
download_data.bytes_transfered = 0;
download_data.timestamp = Util::GetTick();
if (username_param != nullptr)
download_data.host_info.username = username_param;
if (password_param != nullptr)
download_data.host_info.password = password_param;
if (http_server_type_param != nullptr)
download_data.host_info.http_server_type = http_server_type_param;
CONFIG::AddBgDownloadData(download_data);
CONFIG::SaveBgDownloadData();
}
});
svr->Get("/get_download_state", [&](const Request &req, Response &res)
{
json_object *download_list = json_object_new_array();
for (int i=0; i < bg_download_list.size(); i++)
{
json_object *download_item_obj = json_object_new_object();
json_object_object_add(download_item_obj, "path", json_object_new_string(bg_download_list[i].dest_path.c_str()));
json_object_object_add(download_item_obj, "bytes_transfered", json_object_new_uint64(bg_download_list[i].bytes_transfered));
json_object_object_add(download_item_obj, "file_size", json_object_new_uint64(bg_download_list[i].file_size));
json_object_object_add(download_item_obj, "state", json_object_new_int(bg_download_list[i].state));
json_object_object_add(download_item_obj, "timestamp", json_object_new_uint64(bg_download_list[i].timestamp/1000000));
json_object_array_add(download_list, download_item_obj);
}
const char *payload_str = json_object_to_json_string(download_list);
res.status = 200;
res.set_content(payload_str, "application/json");
});
svr->Get("/stop", [&](const Request & /*req*/, Response & /*res*/)
{
svr->stop();
});
svr->Get("/version", [&](const Request & req, Response &res)
{
res.status = 200;
char version[20];
sprintf(version, "%.2f", EZREMOTE_VERSION);
res.set_content(version, "text/html");
});
svr->set_error_handler([](const Request & /*req*/, Response &res)
{
const char *fmt = "<p>Error Status: <span style='color:red;'>%d</span></p>";
char buf[BUFSIZ];
snprintf(buf, sizeof(buf), fmt, res.status);
res.set_content(buf, "text/html");
});
/*
svr->set_logger([](const Request &req, const Response &res)
{
dbglogger_log("%s", log(req, res).c_str());
});
*/
svr->set_payload_max_length(1024 * 1024 * 12);
svr->set_tcp_nodelay(true);
svr->set_mount_point("/", "/");
svr->listen("0.0.0.0", http_server_port);
return NULL;
}
void Start()
{
if (svr == nullptr)
svr = new Server();
if (!svr->is_valid())
{
return;
}
Util::Notify("Starting ezRemote Server %.2f on port %d", EZREMOTE_VERSION, http_server_port);
ServerThread(nullptr);
}
void Stop()
{
if (svr != nullptr)
svr->stop();
}
void StartDownloadThread()
{
pthread_create(&bg_download_thread, NULL, DownloadFilesThread, NULL);
}
bool IsStarted()
{
httplib::Client client = httplib::Client("http://127.0.0.1:6701");
if (auto res = client.Get("/version"))
{
return true;
}
return false;
}
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef EZ_HTTP_SERVER_H
#define EZ_HTTP_SERVER_H
#include "http/httplib.h"
using namespace httplib;
extern Server *svr;
extern int http_server_port;
namespace HttpServer
{
void *ServerThread(void *argp);
void Start();
void Stop();
void StartDownloadThread();
bool IsStarted();
}
#endif
+380
View File
@@ -0,0 +1,380 @@
#ifndef UTIL_H
#define UTIL_H
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
#include <stdarg.h>
#include <sys/time.h>
#include <time.h>
#include "base64.h"
#include "openssl/md5.h"
#include "config.h"
#define SCE_NOTIFICATION_LOCAL_USER_ID_SYSTEM 0xFE
typedef struct notify_request
{
char useless1[45];
char message[3075];
} notify_request_t;
/*
extern "C"
{
int sceKernelSendNotificationRequest(int, notify_request_t *, size_t, int);
int sceNotificationSend(int userId, bool isLogged, const char* payload);
}
*/
namespace Util
{
static void utf16_to_utf8(const uint16_t *src, uint8_t *dst)
{
int i;
for (i = 0; src[i]; i++)
{
if ((src[i] & 0xFF80) == 0)
{
*(dst++) = src[i] & 0xFF;
}
else if ((src[i] & 0xF800) == 0)
{
*(dst++) = ((src[i] >> 6) & 0xFF) | 0xC0;
*(dst++) = (src[i] & 0x3F) | 0x80;
}
else if ((src[i] & 0xFC00) == 0xD800 && (src[i + 1] & 0xFC00) == 0xDC00)
{
*(dst++) = (((src[i] + 64) >> 8) & 0x3) | 0xF0;
*(dst++) = (((src[i] >> 2) + 16) & 0x3F) | 0x80;
*(dst++) = ((src[i] >> 4) & 0x30) | 0x80 | ((src[i + 1] << 2) & 0xF);
*(dst++) = (src[i + 1] & 0x3F) | 0x80;
i += 1;
}
else
{
*(dst++) = ((src[i] >> 12) & 0xF) | 0xE0;
*(dst++) = ((src[i] >> 6) & 0x3F) | 0x80;
*(dst++) = (src[i] & 0x3F) | 0x80;
}
}
*dst = '\0';
}
static void utf8_to_utf16(const uint8_t *src, uint16_t *dst)
{
int i;
for (i = 0; src[i];)
{
if ((src[i] & 0xE0) == 0xE0)
{
*(dst++) = ((src[i] & 0x0F) << 12) | ((src[i + 1] & 0x3F) << 6) | (src[i + 2] & 0x3F);
i += 3;
}
else if ((src[i] & 0xC0) == 0xC0)
{
*(dst++) = ((src[i] & 0x1F) << 6) | (src[i + 1] & 0x3F);
i += 2;
}
else
{
*(dst++) = src[i];
i += 1;
}
}
*dst = '\0';
}
static std::string &Ltrim(std::string &str, std::string chars)
{
str.erase(0, str.find_first_not_of(chars));
return str;
}
static std::string &Rtrim(std::string &str, std::string chars)
{
str.erase(str.find_last_not_of(chars) + 1);
return str;
}
// trim from both ends (in place)
static std::string &Trim(std::string &str, std::string chars)
{
return Ltrim(Rtrim(str, chars), chars);
}
static void ReplaceAll(std::string &data, std::string toSearch, std::string replaceStr)
{
size_t pos = data.find(toSearch);
while (pos != std::string::npos)
{
data.replace(pos, toSearch.size(), replaceStr);
pos = data.find(toSearch, pos + replaceStr.size());
}
}
static std::string ToLower(std::string s)
{
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c)
{ return std::tolower(c); });
return s;
}
static bool EndsWith(std::string const &value, std::string const &ending)
{
if (ending.size() > value.size())
return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
static std::vector<std::string> Split(const std::string &str, const std::string &delimiter)
{
std::string text = std::string(str);
std::vector<std::string> tokens;
size_t pos = 0;
while ((pos = text.find(delimiter)) != std::string::npos)
{
if (text.substr(0, pos).length() > 0)
tokens.push_back(text.substr(0, pos));
text.erase(0, pos + delimiter.length());
}
if (text.length() > 0)
{
tokens.push_back(text);
}
return tokens;
}
static std::string ToString(int value)
{
std::ostringstream myObjectStream;
myObjectStream << value;
return myObjectStream.str();
}
static std::string UrlHash(const std::string &text)
{
std::vector<unsigned char> res(16);
MD5((const unsigned char *)text.c_str(), text.length(), res.data());
std::string out;
Base64::Encode(res.data(), res.size(), out);
Util::ReplaceAll(out, "=", "a");
Util::ReplaceAll(out, "+", "b");
Util::ReplaceAll(out, "/", "c");
out = out + ".pkg";
return out;
}
static uint64_t GetTick()
{
static struct timeval tick;
gettimeofday(&tick, NULL);
return tick.tv_sec * 1000000 + tick.tv_usec;
}
static void Notify(const char *fmt, ...)
{
OrbisNotificationRequest request;
va_list args;
va_start(args, fmt);
vsprintf(request.message, fmt, args);
va_end(args);
request.type = OrbisNotificationRequestType::NotificationRequest;
request.unk3 = 0;
request.useIconImageUri = 0;
request.targetId = -1;
sceKernelSendNotificationRequest(0, &request, sizeof(request), 0);
}
static void append_json_escaped(char *dst, size_t dst_size, const char *src)
{
size_t used = strlen(dst);
if (used >= dst_size)
return;
for (; *src != '\0' && used + 1 < dst_size; ++src)
{
const char *escape = NULL;
char single[2] = {0};
switch (*src)
{
case '\\':
escape = "\\\\";
break;
case '"':
escape = "\\\"";
break;
case '\n':
escape = "\\n";
break;
case '\r':
escape = "\\r";
break;
case '\t':
escape = "\\t";
break;
default:
single[0] = *src;
escape = single;
break;
}
size_t escape_len = strlen(escape);
if (used + escape_len >= dst_size)
break;
memcpy(dst + used, escape, escape_len);
used += escape_len;
dst[used] = '\0';
}
}
static bool RichNotify(uint64_t id, const char *fmt, ...)
{
/*
va_list args;
char message[3072];
char escaped_message[4096];
char payload[8192];
char created_at[32];
char notification_id[32];
va_start(args, fmt);
vsnprintf(message, sizeof message, fmt, args);
va_end(args);
escaped_message[0] = '\0';
append_json_escaped(escaped_message, sizeof(escaped_message), message);
struct tm tm_utc;
time_t now = time(NULL);
gmtime_r(&now, &tm_utc);
strftime(created_at, 32, "%Y-%m-%dT%H:%M:%S.000Z", &tm_utc);
sprintf(notification_id, "%lu", id);
int len = snprintf(
payload, sizeof(payload),
"{\n"
" \"rawData\": {\n"
" \"viewTemplateType\": \"InteractiveToastTemplateB\",\n"
" \"channelType\": \"ServiceFeedback\",\n"
" \"bundleName\": \"ezRemoteClientWelcome\",\n"
" \"useCaseId\": \"IDC\",\n"
" \"soundEffect\": \"none\",\n"
" \"toastOverwriteType\": \"InQueue\",\n"
" \"isImmediate\": true,\n"
" \"priority\": 100,\n"
" \"viewData\": {\n"
" \"icon\": {\n"
" \"type\": \"Url\",\n"
" \"parameters\": {\n"
" \"url\": \"" NOTIFY_ICON_FILE "\"\n"
" }\n"
" },\n"
" \"message\": {\n"
" \"body\": \"%s\"\n"
" },\n"
" \"subMessage\": {\n"
" \"body\": \"ezRemote Client\"\n"
" },\n"
" \"actions\": [\n"
" {\n"
" \"actionName\": \"Go to ezRemote Client\",\n"
" \"actionType\": \"DeepLink\",\n"
" \"defaultFocus\": true,\n"
" \"parameters\": {\n"
" \"actionUrl\": \"http://localhost:8080/hbldr?path=%s\"\n"
" }\n"
" }\n"
" ]\n"
" },\n"
" \"platformViews\": {\n"
" \"previewDisabled\": {\n"
" \"viewData\": {\n"
" \"icon\": {\n"
" \"type\": \"Predefined\",\n"
" \"parameters\": {\n"
" \"icon\": \"community\"\n"
" }\n"
" },\n"
" \"message\": {\n"
" \"body\": \"%s\"\n"
" }\n"
" }\n"
" }\n"
" }\n"
" },\n"
" \"createdDateTime\": \"%s\",\n"
" \"localNotificationId\": \"%s\"\n"
"}",
escaped_message, EZREMOTE_VERSION, CLIENT_ELF_PATH, escaped_message, created_at,
notification_id);
if (len < 0 || (size_t)len >= sizeof(payload))
return false;
int rc = sceNotificationSend(SCE_NOTIFICATION_LOCAL_USER_ID_SYSTEM, true,
payload);
return rc == 0;
*/
return 0;
}
static size_t NthOccurrence(const std::string &str, const std::string &findMe, int nth, size_t start_pos = 0, size_t end_pos = INT_MAX)
{
size_t prev_pos = std::string::npos;
size_t pos = start_pos;
int cnt = 0;
while (cnt != nth)
{
pos += 1;
pos = str.find(findMe, pos);
if (pos > end_pos)
return prev_pos;
if (pos == std::string::npos)
{
if (cnt == 0)
return std::string::npos;
else
break;
}
prev_pos = pos;
cnt++;
}
return pos;
}
static size_t CountOccurrence(const std::string &str, const std::string &findMe, size_t start_pos = 0, size_t end_pos = INT_MAX)
{
size_t pos = start_pos;
int cnt = 0;
while (true)
{
pos += 1;
pos = str.find(findMe, pos);
if (pos > end_pos)
return cnt;
if (pos == std::string::npos)
{
break;
}
pos += 1;
cnt++;
}
return cnt;
}
}
#endif