From 32b942c6b252ed8e38a9957a1b2541677747ddd6 Mon Sep 17 00:00:00 2001
From: Sorunome <+@sorunome.de>
Date: Wed, 1 May 2024 16:41:41 +0200
Subject: [PATCH] start migrate to nid and allow server messages

---
 .gitmodules           |  3 +++
 Makefile              |  2 +-
 server/database.py    | 16 ++++++++++++++--
 server/server.py      | 14 +++++++++++++-
 source/api.h          |  4 ++--
 source/curl-handler.c | 30 ++++++++++++++++++++++++++++++
 source/hmac_sha256    |  1 +
 source/main.c         |  4 ----
 source/strings.c      |  4 ++++
 version.env           |  2 +-
 10 files changed, 69 insertions(+), 11 deletions(-)
 create mode 100644 .gitmodules
 create mode 160000 source/hmac_sha256

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..f7fe4ee
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "source/hmac_sha256"]
+	path = source/hmac_sha256
+	url = https://github.com/h5p9sl/hmac_sha256
diff --git a/Makefile b/Makefile
index e1ab56e..6895d03 100644
--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,7 @@ include $(DEVKITARM)/3ds_rules
 TARGET			:=	netpass
 OUTDIR			:=	out
 BUILD			:=	build
-SOURCES			:=	source source/scenes
+SOURCES			:=	source source/scenes source/hmac_sha256
 DATA			:=	data
 INCLUDES		:=	include
 GRAPHICS		:=	gfx
diff --git a/server/database.py b/server/database.py
index 9a9becd..fb8b798 100644
--- a/server/database.py
+++ b/server/database.py
@@ -96,6 +96,13 @@ class Database:
 				count INT NOT NULL DEFAULT 1
 			);
 			CREATE UNIQUE INDEX IF NOT EXISTS title_unique ON title (title_id, title_name);
+
+			CREATE TABLE IF NOT EXISTS map_mac_nid (
+				mac BIGINT NOT NULL,
+				nid VARCHAR(50) NOT NULL
+			);
+			CREATE UNIQUE INDEX IF NOT EXISTS map_mac_nid_mac ON map_mac_nid (mac);
+			CREATE UNIQUE INDEX IF NOT EXISTS map_mac_nid_nid ON map_mac_nid (nid);
 			COMMIT;
 			""")
 		self.con().commit()
@@ -119,14 +126,19 @@ class Database:
 		ON CONFLICT (title_id, reason_id) DO UPDATE SET count = r.count + 1
 		""", (title_id, msg, research_id))
 
+	def store_nid(self, mac, nid):
+		try:
+			with self.con().cursor() as cur:
+				cur.execute("INSERT INTO map_mac_nid (mac, nid) VALUES (%s, %s) ON CONFLICT DO NOTHING", (mac, nid))
+		finally:
+			self.con().commit()
+
 	def store_mboxlist(self, mac, mboxlist):
 		try:
 			with self.con().cursor() as cur:
 				cur.execute("DELETE FROM mboxlist WHERE mac = %s", (mac,))
 				for title_id in mboxlist.title_ids:
 					cur.execute("INSERT INTO mboxlist (mac, title_id, time) VALUES (%s, %s, %s)", (mac, title_id, math.floor(time.time())))
-		except Exception as e:
-			print(e)
 		finally:
 			self.con().commit()
 
diff --git a/server/server.py b/server/server.py
index 5f58ecf..d8e4391 100644
--- a/server/server.py
+++ b/server/server.py
@@ -57,6 +57,12 @@ class StreetPassServer(BaseHTTPRequestHandler):
 		self.wfile.write(bytes(errmsg, "utf-8"))
 	def write_str(self, s):
 		self.wfile.write(bytes(s, "utf-8"))
+	def pong(self):
+		self.send_response(200)
+		self.send_header("Content-Type", "text/plain")
+		#self.send_header("3ds-netpass-msg", self.headers['3ds-netpass-version'])
+		self.end_headers()
+		self.write_str("pong")
 	def get_mac(self):
 		mac = self.headers['3ds-mac']
 		try:
@@ -70,6 +76,12 @@ class StreetPassServer(BaseHTTPRequestHandler):
 			mac = struct.unpack('<q', mac + b'\x00\x00')[0]
 		except:
 			return self.write_response(400, "Invalid mac")
+		nid = self.headers['3ds-nid']
+		try:
+			if len(nid) < 50:
+				database.store_nid(mac, nid)
+		except:
+			pass
 		return mac
 	def upload_new_messages(self):
 		# first verify the headers needed
@@ -251,7 +263,7 @@ class StreetPassServer(BaseHTTPRequestHandler):
 			if self.path == "/location/current":
 				return self.get_location()
 			if self.path == "/ping":
-				return self.write_response(200, "pong")
+				return self.pong()
 			if self.path == "/data":
 				return self.get_data()
 			self.write_response(404, "path not found")
diff --git a/source/api.h b/source/api.h
index 3dc173d..7b0d9ad 100644
--- a/source/api.h
+++ b/source/api.h
@@ -21,8 +21,8 @@
 #include <3ds.h>
 #include "curl-handler.h"
 
-//#define BASE_URL "https://streetpass.sorunome.de"
-#define BASE_URL "http://10.6.42.119:8080"
+#define BASE_URL "https://streetpass.sorunome.de"
+//#define BASE_URL "http://10.6.42.119:8080"
 
 #define lambda(return_type, function_body) \
 ({ \
diff --git a/source/curl-handler.c b/source/curl-handler.c
index 8bc0b42..c00fb47 100644
--- a/source/curl-handler.c
+++ b/source/curl-handler.c
@@ -19,6 +19,8 @@
 #include "curl-handler.h"
 #include "cecd.h"
 #include "api.h"
+#include "hmac_sha256/hmac_sha256.h"
+#include "base64.h"
 #include <malloc.h>
 #include <string.h>
 #include <stdlib.h>
@@ -31,6 +33,7 @@ static u32 *SOC_buffer = NULL;
 static Thread curl_multi_thread;
 static bool running = false;
 static u8 mac[6] = {0};
+static char* netpass_id;
 
 #define CURL_HANDLE_STATUS_FREE 0
 #define CURL_HANDLE_STATUS_RESERVED 1
@@ -93,6 +96,17 @@ size_t curlWrite(void *data, size_t size, size_t nmemb, void* ptr) {
 	return size*nmemb;
 }
 
+size_t curlHeader(void *data, size_t size, size_t nmemb, void* ptr) {
+	char buf[size*nmemb + 1];
+	memcpy(buf, data, size*nmemb);
+	buf[size*nmemb] = '\0';
+	static const char header_name[] = "3ds-netpass-msg: ";
+	if (strncmp(header_name, buf, strlen(header_name)) == 0) {
+		printf("%s\n", buf + strlen(header_name));
+	}
+	return size*nmemb;
+}
+
 void curlFreeHandler(int offset) {
 	handles[offset].status = CURL_HANDLE_STATUS_RESET;
 }
@@ -189,6 +203,12 @@ void curl_multi_loop_request_setup(int i) {
 		header_mac_i += sprintf(header_mac_i, "%02X", mac[j]);
 	}
 	headers = curl_slist_append(headers, header_mac);
+	char header_netpass_id[100];
+	snprintf(header_netpass_id, 100, "3ds-nid: %s", netpass_id);
+	headers = curl_slist_append(headers, header_netpass_id);
+	char header_netpass_version[100];
+	snprintf(header_netpass_version, 100, "3ds-netpass-version: v%d.%d.%d", _VERSION_MAJOR_, _VERSION_MINOR_, _VERSION_MICRO_);
+	headers = curl_slist_append(headers, header_netpass_version);
 	if (h->title_name && !h->file_reply) {
 		char header_title_name[225];
 		snprintf(header_title_name, 225, "3ds-title-name: %s", h->title_name);
@@ -216,6 +236,8 @@ void curl_multi_loop_request_setup(int i) {
 	curl_easy_setopt(h->handle, CURLOPT_NOSIGNAL, 0);
 	curl_easy_setopt(h->handle, CURLOPT_SSL_VERIFYPEER, 1);
 	curl_easy_setopt(h->handle, CURLOPT_CAINFO, "romfs:/certs.pem");
+	curl_easy_setopt(h->handle, CURLOPT_HEADERFUNCTION, curlHeader);
+	curl_easy_setopt(h->handle, CURLOPT_HEADERDATA, NULL);
 
 	if (h->file_reply) {
 		curl_easy_setopt(h->handle, CURLOPT_WRITEFUNCTION, fwrite);
@@ -288,9 +310,16 @@ Result curlInit(void) {
 	if (R_FAILED(res)) return res;
 	curl_global_init(CURL_GLOBAL_ALL);
 
+	u32 device_id;
+	res = AM_GetDeviceId(&device_id);
+	if (R_FAILED(res)) return res;
 	res = getMac(mac);
 	if (R_FAILED(res)) return res;
 
+	u8 netpass_id_buf[32];
+	hmac_sha256(&device_id, 4, mac, 6, netpass_id_buf, 32);
+	netpass_id = b64encode(netpass_id_buf, 32);
+
 	curl_multi_thread = threadCreate(curl_multi_loop, NULL, 8*1024, main_thread_prio()-1, -2, false);
 
 	return res;
@@ -299,6 +328,7 @@ Result curlInit(void) {
 void curlExit(void) {
 	running = false;
 	//threadFree(curl_multi_thread);
+	free(netpass_id);
 	curl_global_cleanup();
 	socExit();
 }
\ No newline at end of file
diff --git a/source/hmac_sha256 b/source/hmac_sha256
new file mode 160000
index 0000000..9445307
--- /dev/null
+++ b/source/hmac_sha256
@@ -0,0 +1 @@
+Subproject commit 9445307885b86fb997b10f49ada5bee47496950a
diff --git a/source/main.c b/source/main.c
index 4db2dec..aa197fe 100644
--- a/source/main.c
+++ b/source/main.c
@@ -37,10 +37,6 @@ int main() {
 	romfsInit();
 	init_main_thread_prio();
 
-	u32 device_id;
-	AM_GetDeviceId(&device_id);
-	printf("Device ID: %ld\n", device_id);
-
 	cecdInit();
 	curlInit();
 	srand(time(NULL));
diff --git a/source/strings.c b/source/strings.c
index 95d4e8e..75ae183 100644
--- a/source/strings.c
+++ b/source/strings.c
@@ -144,6 +144,7 @@ LanguageString str_settings = {
 	{CFG_LANGUAGE_ES, 0},
 	{CFG_LANGUAGE_RU, 0},
 	{CFG_LANGUAGE_PL, 0},
+	{CFG_LANGUAGE_FR, 0},
 };
 LanguageString str_download_data = {
 	{CFG_LANGUAGE_EN, "Download personal data"},
@@ -152,6 +153,7 @@ LanguageString str_download_data = {
 	{CFG_LANGUAGE_ES, 0},
 	{CFG_LANGUAGE_RU, 0},
 	{CFG_LANGUAGE_PL, 0},
+	{CFG_LANGUAGE_FR, 0},
 };
 LanguageString str_delete_data = {
 	{CFG_LANGUAGE_EN, "Delete personal data"},
@@ -160,6 +162,7 @@ LanguageString str_delete_data = {
 	{CFG_LANGUAGE_ES, 0},
 	{CFG_LANGUAGE_RU, 0},
 	{CFG_LANGUAGE_PL, 0},
+	{CFG_LANGUAGE_FR, 0},
 };
 LanguageString str_back = {
 	{CFG_LANGUAGE_EN, "Back"},
@@ -168,6 +171,7 @@ LanguageString str_back = {
 	{CFG_LANGUAGE_ES, 0},
 	{CFG_LANGUAGE_RU, 0},
 	{CFG_LANGUAGE_PL, 0},
+	{CFG_LANGUAGE_FR, 0},
 };
 
 static u8 _language;
diff --git a/version.env b/version.env
index 7c6db5a..6960237 100644
--- a/version.env
+++ b/version.env
@@ -1,3 +1,3 @@
 NETPASS_VERSION_MAJOR=0
 NETPASS_VERSION_MINOR=2
-NETPASS_VERSION_MICRO=2
\ No newline at end of file
+NETPASS_VERSION_MICRO=3
\ No newline at end of file
-- 
GitLab