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
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)
If you are on Windows, you can drag and drop a CIA file or directory onto **servefiles.bat**.
**Usage**: python servefiles.py (ip) (file/directory)

View File

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

View File

@ -1,33 +1,30 @@
import atexit
import os
import socket
import struct
import sys
import tempfile
import threading
import time
import urllib
import netifaces
import qrcode
from PIL import ImageTk
try:
from SimpleHTTPServer import SimpleHTTPRequestHandler
from SocketServer import TCPServer
from Tkinter import Tk, Frame, Label, BitmapImage
from urlparse import urljoin
from urllib import pathname2url, quote
except ImportError:
from http.server import SimpleHTTPRequestHandler
from socketserver import TCPServer
from tkinter import Tk, Frame, Label, BitmapImage
from urllib.parse import urljoin, quote
from urllib.request import pathname2url
if len(sys.argv) < 2:
print("Please specify a file/directory.")
if len(sys.argv) < 3:
print("Usage: " + sys.argv[0] + " <ip> <file/directory>")
sys.exit(1)
directory = sys.argv[1]
ip = sys.argv[1]
directory = sys.argv[2]
if not os.path.exists(directory):
print(directory + ": No such file or directory.")
@ -35,19 +32,19 @@ if not os.path.exists(directory):
print("Preparing data...")
baseUrl = netifaces.ifaddresses(netifaces.gateways()['default'][netifaces.AF_INET][1])[2][0]['addr'] + ":8080/"
qrData = ""
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/"
payload = ""
if os.path.isfile(directory):
if directory.endswith(('.cia', '.tik')):
qrData += baseUrl + quote(os.path.basename(directory))
payload += baseUrl + quote(os.path.basename(directory))
directory = os.path.dirname(directory)
else:
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.")
sys.exit(1)
@ -56,37 +53,38 @@ if not directory == "":
print("")
print("URLS:")
print(qrData)
print(payload)
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...")
server = TCPServer(("", 8080), SimpleHTTPRequestHandler)
thread = threading.Thread(target=server.serve_forever)
thread.start()
atexit.register(server.shutdown)
print("Displaying QR code...")
try:
print("Sending URL(s) to " + ip + ":5000...")
root = Tk()
root.title("QR Code")
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ip, 5000))
frame = Frame(root)
frame.pack()
payloadBytes = bytes(payload, "ascii")
networkPayload = struct.pack('!L', len(payloadBytes)) + payloadBytes
qrBitmap = ImageTk.PhotoImage(qrImage)
qrLabel = Label(frame, image=qrBitmap)
qrLabel.pack()
sentLength = 0
while sentLength < len(networkPayload):
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...")

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_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);

View File

@ -10,5 +10,5 @@ void action_install_titledb(linked_list* items, list_item* selected) {
char url[128];
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 {
char urls[URLS_MAX][URL_MAX];
void* finishedData;
void (*finished)(void* data);
bool cdn;
bool cdnDecided;
@ -31,6 +34,14 @@ typedef struct {
data_op_data installInfo;
} 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) {
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);
}
action_url_install_free_data(installData);
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);
} else {
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));
if(data == NULL) {
error_display(NULL, NULL, "Failed to allocate QR install data.");
error_display(NULL, NULL, "Failed to allocate URL install data.");
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->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);
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;
}
}
@ -255,6 +255,7 @@ void remoteinstall_scan_qr_code() {
typedef struct {
int serverSocket;
int clientSocket;
} remoteinstall_network_data;
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;
}
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) {
remoteinstall_network_close_client(data);
if(data->serverSocket != 0) {
close(data->serverSocket);
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);
if(sock >= 0) {
u32 size = 0;
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).");
}
networkData->clientSocket = sock;
free(urls);
} else {
error_display(NULL, NULL, "Failed to allocate URL buffer.");
}
} else {
error_display(NULL, NULL, "Payload too large.");
}
} else {
u32 size = 0;
if(remoteinstall_network_recvwait(networkData->clientSocket, &size, sizeof(size), 0) != sizeof(size)) {
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) {
if(errno == 22 || errno == 115) {
ui_pop();
@ -355,9 +397,6 @@ void remoteinstall_receive_urls_network() {
data->serverSocket = sock;
int bufSize = 1024 * 32;
setsockopt(data->serverSocket, SOL_SOCKET, SO_RCVBUF, &bufSize, sizeof(bufSize));
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(5000);
@ -393,7 +432,7 @@ void remoteinstall_manually_enter_urls() {
if(swkbdInputText(&swkbd, textBuf, sizeof(textBuf)) == SWKBD_BUTTON_CONFIRM) {
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;
}
}
@ -401,7 +440,7 @@ void remoteinstall_manually_enter_urls() {
void remoteinstall_repeat_last_request() {
char textBuf[4096];
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 {
prompt_display("Failure", "No previously requested URL(s) could be found.", COLOR_TEXT, false, NULL, NULL, NULL);
}