Polish up URL sending protocol, adapt servefiles to send URLs over socket.

This commit is contained in:
Steveice10 2016-12-23 23:10:39 -08:00
parent d06374d838
commit 13a88f7adb
7 changed files with 123 additions and 68 deletions

View File

@ -1,7 +1,5 @@
# servefiles # servefiles
Simple Python script for serving local files to FBI's QR code installer. Requires [Python](https://www.python.org/downloads/), [Pillow](https://pypi.python.org/pypi/Pillow), [qrcode](https://pypi.python.org/pypi/qrcode), and [netifaces](https://pypi.python.org/pypi/netifaces). Simple Python script for serving local files to FBI's remote installer. Requires [Python](https://www.python.org/downloads/).
**Usage**: python servefiles.py (file/directory) **Usage**: python servefiles.py (ip) (file/directory)
If you are on Windows, you can drag and drop a CIA file or directory onto **servefiles.bat**.

View File

@ -1 +0,0 @@
python servefiles.py %1

View File

@ -1,33 +1,30 @@
import atexit import atexit
import os import os
import socket
import struct
import sys import sys
import tempfile import tempfile
import threading import threading
import time
import urllib import urllib
import netifaces
import qrcode
from PIL import ImageTk
try: try:
from SimpleHTTPServer import SimpleHTTPRequestHandler from SimpleHTTPServer import SimpleHTTPRequestHandler
from SocketServer import TCPServer from SocketServer import TCPServer
from Tkinter import Tk, Frame, Label, BitmapImage
from urlparse import urljoin from urlparse import urljoin
from urllib import pathname2url, quote from urllib import pathname2url, quote
except ImportError: except ImportError:
from http.server import SimpleHTTPRequestHandler from http.server import SimpleHTTPRequestHandler
from socketserver import TCPServer from socketserver import TCPServer
from tkinter import Tk, Frame, Label, BitmapImage
from urllib.parse import urljoin, quote from urllib.parse import urljoin, quote
from urllib.request import pathname2url from urllib.request import pathname2url
if len(sys.argv) < 2: if len(sys.argv) < 3:
print("Please specify a file/directory.") print("Usage: " + sys.argv[0] + " <ip> <file/directory>")
sys.exit(1) sys.exit(1)
directory = sys.argv[1] ip = sys.argv[1]
directory = sys.argv[2]
if not os.path.exists(directory): if not os.path.exists(directory):
print(directory + ": No such file or directory.") print(directory + ": No such file or directory.")
@ -35,19 +32,19 @@ if not os.path.exists(directory):
print("Preparing data...") print("Preparing data...")
baseUrl = netifaces.ifaddresses(netifaces.gateways()['default'][netifaces.AF_INET][1])[2][0]['addr'] + ":8080/" baseUrl = [(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1] + ":8080/"
qrData = "" payload = ""
if os.path.isfile(directory): if os.path.isfile(directory):
if directory.endswith(('.cia', '.tik')): if directory.endswith(('.cia', '.tik')):
qrData += baseUrl + quote(os.path.basename(directory)) payload += baseUrl + quote(os.path.basename(directory))
directory = os.path.dirname(directory) directory = os.path.dirname(directory)
else: else:
for file in [ file for file in next(os.walk(directory))[2] if file.endswith(('.cia', '.tik')) ]: for file in [ file for file in next(os.walk(directory))[2] if file.endswith(('.cia', '.tik')) ]:
qrData += baseUrl + quote(file) + "\n" payload += baseUrl + quote(file) + "\n"
if len(qrData) == 0: if len(payload) == 0:
print("No files to serve.") print("No files to serve.")
sys.exit(1) sys.exit(1)
@ -56,37 +53,38 @@ if not directory == "":
print("") print("")
print("URLS:") print("URLS:")
print(qrData) print(payload)
print("") print("")
print("Generating QR code...")
try:
qrImage = qrcode.make(qrData, box_size=5)
except qrcode.exceptions.DataOverflowError:
print("Error: URL list too large for a QR code. Try reducing file name lengths or the number of files to send.")
sys.exit(1)
print("Opening HTTP server on port 8080...") print("Opening HTTP server on port 8080...")
server = TCPServer(("", 8080), SimpleHTTPRequestHandler) server = TCPServer(("", 8080), SimpleHTTPRequestHandler)
thread = threading.Thread(target=server.serve_forever) thread = threading.Thread(target=server.serve_forever)
thread.start() thread.start()
atexit.register(server.shutdown)
print("Displaying QR code...") try:
print("Sending URL(s) to " + ip + ":5000...")
root = Tk() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
root.title("QR Code") sock.connect((ip, 5000))
frame = Frame(root) payloadBytes = bytes(payload, "ascii")
frame.pack() networkPayload = struct.pack('!L', len(payloadBytes)) + payloadBytes
qrBitmap = ImageTk.PhotoImage(qrImage) sentLength = 0
qrLabel = Label(frame, image=qrBitmap) while sentLength < len(networkPayload):
qrLabel.pack() sent = sock.send(networkPayload[sentLength:])
if sent == 0:
raise RuntimeError("Socket connection broken.")
sentLength += sent
root.mainloop() while len(sock.recv(1)) < 1:
time.sleep(0.05)
sock.close()
except Exception as e:
print("Error: " + str(e))
print("Shutting down HTTP server...") print("Shutting down HTTP server...")

View File

@ -49,5 +49,6 @@ void action_import_secure_value(linked_list* items, list_item* selected);
void action_export_secure_value(linked_list* items, list_item* selected); void action_export_secure_value(linked_list* items, list_item* selected);
void action_delete_secure_value(linked_list* items, list_item* selected); void action_delete_secure_value(linked_list* items, list_item* selected);
void action_url_install(const char* confirmMessage, const char* urls); void action_url_install(const char* confirmMessage, const char* urls, void* finishedData, void (*finished)(void* data));
void action_install_titledb(linked_list* items, list_item* selected); void action_install_titledb(linked_list* items, list_item* selected);

View File

@ -10,5 +10,5 @@ void action_install_titledb(linked_list* items, list_item* selected) {
char url[128]; char url[128];
snprintf(url, sizeof(url), "https://api.titledb.com/v0/proxy/%016llX", ((titledb_info*) selected->data)->titleId); snprintf(url, sizeof(url), "https://api.titledb.com/v0/proxy/%016llX", ((titledb_info*) selected->data)->titleId);
action_url_install("Install the selected title from TitleDB?", url); action_url_install("Install the selected title from TitleDB?", url, NULL, NULL);
} }

View File

@ -19,6 +19,9 @@
typedef struct { typedef struct {
char urls[URLS_MAX][URL_MAX]; char urls[URLS_MAX][URL_MAX];
void* finishedData;
void (*finished)(void* data);
bool cdn; bool cdn;
bool cdnDecided; bool cdnDecided;
@ -31,6 +34,14 @@ typedef struct {
data_op_data installInfo; data_op_data installInfo;
} url_install_data; } url_install_data;
static void action_url_install_free_data(url_install_data* data) {
if(data->finished != NULL) {
data->finished(data->finishedData);
}
free(data);
}
static void action_url_install_cdn_check_onresponse(ui_view* view, void* data, bool response) { static void action_url_install_cdn_check_onresponse(ui_view* view, void* data, bool response) {
url_install_data* installData = (url_install_data*) data; url_install_data* installData = (url_install_data*) data;
@ -248,6 +259,8 @@ static void action_url_install_install_update(ui_view* view, void* data, float*
prompt_display("Success", "Install finished.", COLOR_TEXT, false, NULL, NULL, NULL); prompt_display("Success", "Install finished.", COLOR_TEXT, false, NULL, NULL, NULL);
} }
action_url_install_free_data(installData);
return; return;
} }
@ -268,14 +281,18 @@ static void action_url_install_confirm_onresponse(ui_view* view, void* data, boo
info_display("Installing From URL(s)", "Press B to cancel.", true, data, action_url_install_install_update, NULL); info_display("Installing From URL(s)", "Press B to cancel.", true, data, action_url_install_install_update, NULL);
} else { } else {
error_display_res(NULL, NULL, res, "Failed to initiate installation."); error_display_res(NULL, NULL, res, "Failed to initiate installation.");
action_url_install_free_data(installData);
} }
} else {
action_url_install_free_data(installData);
} }
} }
void action_url_install(const char* confirmMessage, const char* urls) { void action_url_install(const char* confirmMessage, const char* urls, void* finishedData, void (*finished)(void* data)) {
url_install_data* data = (url_install_data*) calloc(1, sizeof(url_install_data)); url_install_data* data = (url_install_data*) calloc(1, sizeof(url_install_data));
if(data == NULL) { if(data == NULL) {
error_display(NULL, NULL, "Failed to allocate QR install data."); error_display(NULL, NULL, "Failed to allocate URL install data.");
return; return;
} }
@ -313,6 +330,9 @@ void action_url_install(const char* confirmMessage, const char* urls) {
} }
} }
data->finishedData = finishedData;
data->finished = finished;
data->cdn = false; data->cdn = false;
data->cdnDecided = false; data->cdnDecided = false;

View File

@ -202,7 +202,7 @@ static void remoteinstall_qr_update(ui_view* view, void* data, float* progress,
remoteinstall_set_last_urls((const char*) qrData.payload); remoteinstall_set_last_urls((const char*) qrData.payload);
action_url_install("Install from the scanned QR code?", (const char*) qrData.payload); action_url_install("Install from the scanned QR code?", (const char*) qrData.payload, NULL, NULL);
return; return;
} }
} }
@ -255,6 +255,7 @@ void remoteinstall_scan_qr_code() {
typedef struct { typedef struct {
int serverSocket; int serverSocket;
int clientSocket;
} remoteinstall_network_data; } remoteinstall_network_data;
static int remoteinstall_network_recvwait(int sockfd, void* buf, size_t len, int flags) { static int remoteinstall_network_recvwait(int sockfd, void* buf, size_t len, int flags) {
@ -269,7 +270,33 @@ static int remoteinstall_network_recvwait(int sockfd, void* buf, size_t len, int
return ret < 0 ? ret : (int) read; return ret < 0 ? ret : (int) read;
} }
static int remoteinstall_network_sendwait(int sockfd, void* buf, size_t len, int flags) {
errno = 0;
int ret = 0;
size_t written = 0;
while(((ret = send(sockfd, buf + written, len - written, flags)) >= 0 && (written += ret) < len) || errno == EAGAIN) {
errno = 0;
}
return ret < 0 ? ret : (int) written;
}
static void remoteinstall_network_close_client(void* data) {
remoteinstall_network_data* networkData = (remoteinstall_network_data*) data;
if(networkData->clientSocket != 0) {
u8 ack = 0;
remoteinstall_network_sendwait(networkData->clientSocket, &ack, sizeof(ack), 0);
close(networkData->clientSocket);
networkData->clientSocket = 0;
}
}
static void remoteinstall_network_free_data(remoteinstall_network_data* data) { static void remoteinstall_network_free_data(remoteinstall_network_data* data) {
remoteinstall_network_close_client(data);
if(data->serverSocket != 0) { if(data->serverSocket != 0) {
close(data->serverSocket); close(data->serverSocket);
data->serverSocket = 0; data->serverSocket = 0;
@ -295,29 +322,44 @@ static void remoteinstall_network_update(ui_view* view, void* data, float* progr
int sock = accept(networkData->serverSocket, (struct sockaddr*) &client, &clientLen); int sock = accept(networkData->serverSocket, (struct sockaddr*) &client, &clientLen);
if(sock >= 0) { if(sock >= 0) {
u32 size = 0; networkData->clientSocket = sock;
if(remoteinstall_network_recvwait(sock, &size, sizeof(size), 0) == sizeof(size)) {
if(size < 128 * 1024) {
char* urls = (char*) calloc(size, sizeof(char));
if(urls != NULL) {
if(remoteinstall_network_recvwait(sock, urls, size, 0) == size) {
action_url_install("Install from the received URL(s)?", urls);
} else {
error_display_errno(NULL, NULL, errno, "Failed to read URL(s).");
}
free(urls); u32 size = 0;
} else { if(remoteinstall_network_recvwait(networkData->clientSocket, &size, sizeof(size), 0) != sizeof(size)) {
error_display(NULL, NULL, "Failed to allocate URL buffer.");
}
} else {
error_display(NULL, NULL, "Payload too large.");
}
} else {
error_display_errno(NULL, NULL, errno, "Failed to read payload length."); error_display_errno(NULL, NULL, errno, "Failed to read payload length.");
remoteinstall_network_close_client(data);
return;
} }
close(sock); size = ntohl(size);
if(size >= 128 * 1024) {
error_display(NULL, NULL, "Payload too large.");
remoteinstall_network_close_client(data);
return;
}
char* urls = (char*) calloc(size, sizeof(char));
if(urls == NULL) {
error_display(NULL, NULL, "Failed to allocate URL buffer.");
remoteinstall_network_close_client(data);
return;
}
if(remoteinstall_network_recvwait(networkData->clientSocket, urls, size, 0) != size) {
error_display_errno(NULL, NULL, errno, "Failed to read URL(s).");
free(urls);
remoteinstall_network_close_client(data);
return;
}
remoteinstall_set_last_urls(urls);
action_url_install("Install from the received URL(s)?", urls, data, remoteinstall_network_close_client);
free(urls);
} else if(errno != EAGAIN) { } else if(errno != EAGAIN) {
if(errno == 22 || errno == 115) { if(errno == 22 || errno == 115) {
ui_pop(); ui_pop();
@ -355,9 +397,6 @@ void remoteinstall_receive_urls_network() {
data->serverSocket = sock; data->serverSocket = sock;
int bufSize = 1024 * 32;
setsockopt(data->serverSocket, SOL_SOCKET, SO_RCVBUF, &bufSize, sizeof(bufSize));
struct sockaddr_in server; struct sockaddr_in server;
server.sin_family = AF_INET; server.sin_family = AF_INET;
server.sin_port = htons(5000); server.sin_port = htons(5000);
@ -393,7 +432,7 @@ void remoteinstall_manually_enter_urls() {
if(swkbdInputText(&swkbd, textBuf, sizeof(textBuf)) == SWKBD_BUTTON_CONFIRM) { if(swkbdInputText(&swkbd, textBuf, sizeof(textBuf)) == SWKBD_BUTTON_CONFIRM) {
remoteinstall_set_last_urls(textBuf); remoteinstall_set_last_urls(textBuf);
action_url_install("Install from the entered URL(s)?", textBuf); action_url_install("Install from the entered URL(s)?", textBuf, NULL, NULL);
return; return;
} }
} }
@ -401,7 +440,7 @@ void remoteinstall_manually_enter_urls() {
void remoteinstall_repeat_last_request() { void remoteinstall_repeat_last_request() {
char textBuf[4096]; char textBuf[4096];
if(remoteinstall_get_last_urls(textBuf, sizeof(textBuf))) { if(remoteinstall_get_last_urls(textBuf, sizeof(textBuf))) {
action_url_install("Install from the last requested URL(s)?", textBuf); action_url_install("Install from the last requested URL(s)?", textBuf, NULL, NULL);
} else { } else {
prompt_display("Failure", "No previously requested URL(s) could be found.", COLOR_TEXT, false, NULL, NULL, NULL); prompt_display("Failure", "No previously requested URL(s) could be found.", COLOR_TEXT, false, NULL, NULL, NULL);
} }