/*** Set SSL options for a context. @function :setSSLOptions @tparam boolean disableVerify disable server certificate verification if `true` @tparam[opt=false] boolean tlsv10 use TLS v1.0 if `true` */ static int httpc_setSSLOptions(lua_State *L) { httpcContext *context = lua_touserdata(L, 1); bool disVer = lua_toboolean(L, 2); bool tsl10 = false; if (lua_isboolean(L, 3)) tsl10 = lua_toboolean(L, 3); httpcSetSSLOpt(context, (disVer?SSLCOPT_DisableVerify:0)|(tsl10?SSLCOPT_TLSv10:0)); return 0; }
static Result action_url_install_open_src(void* data, u32 index, u32* handle) { url_install_data* installData = (url_install_data*) data; Result res = 0; httpcContext* context = (httpcContext*) calloc(1, sizeof(httpcContext)); if(context != NULL) { if(R_SUCCEEDED(res = httpcOpenContext(context, HTTPC_METHOD_GET, installData->urls[index], 1))) { char userAgent[128]; snprintf(userAgent, sizeof(userAgent), "Mozilla/5.0 (Nintendo 3DS; Mobile; rv:10.0) Gecko/20100101 FBI/%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO); if(R_SUCCEEDED(res = httpcSetSSLOpt(context, SSLCOPT_DisableVerify)) && R_SUCCEEDED(res = httpcAddRequestHeaderField(context, "User-Agent", userAgent)) && R_SUCCEEDED(res = httpcBeginRequest(context)) && R_SUCCEEDED(res = httpcGetResponseStatusCode(context, &installData->responseCode, 0))) { if(installData->responseCode == 200) { *handle = (u32) context; } else if(installData->responseCode == 301 || installData->responseCode == 302 || installData->responseCode == 303) { memset(installData->urls[index], '\0', URL_MAX); if(R_SUCCEEDED(res = httpcGetResponseHeader(context, "Location", installData->urls[index], URL_MAX))) { httpcCloseContext(context); free(context); return action_url_install_open_src(data, index, handle); } } else { res = R_FBI_HTTP_RESPONSE_CODE; } } if(R_FAILED(res)) { httpcCloseContext(context); } } if(R_FAILED(res)) { free(context); } } else { res = R_FBI_OUT_OF_MEMORY; } return res; }
static Result action_install_cdn_open_src(void* data, u32 index, u32* handle) { install_cdn_data* installData = (install_cdn_data*) data; Result res = 0; httpcContext* context = (httpcContext*) calloc(1, sizeof(httpcContext)); if(context != NULL) { char url[256]; if(index == 0) { snprintf(url, 256, "http://ccs.cdn.c.shop.nintendowifi.net/ccs/download/%016llX/tmd", installData->ticket->titleId); } else { snprintf(url, 256, "http://ccs.cdn.c.shop.nintendowifi.net/ccs/download/%016llX/%08lX", installData->ticket->titleId, installData->contentIds[index - 1]); } if(R_SUCCEEDED(res = httpcOpenContext(context, HTTPC_METHOD_GET, url, 1))) { httpcSetSSLOpt(context, SSLCOPT_DisableVerify); if(R_SUCCEEDED(res = httpcBeginRequest(context)) && R_SUCCEEDED(res = httpcGetResponseStatusCode(context, &installData->responseCode, 0))) { if(installData->responseCode == 200) { *handle = (u32) context; } else { res = R_FBI_HTTP_RESPONSE_CODE; } } if(R_FAILED(res)) { httpcCloseContext(context); } } if(R_FAILED(res)) { free(context); } } else { res = R_FBI_OUT_OF_MEMORY; } return res; }
Result DownloadTitle(std::string titleId, std::string encTitleKey, std::string titleName, std::string region) { // Convert the titleid to a u64 for later use char* nTitleId = parse_string(titleId); u64 uTitleId = u8_to_u64((u8*)nTitleId, BIG_ENDIAN); free (nTitleId); // Wait for wifi to be available u32 wifi = 0; Result ret = 0; Result res = 0; while(R_SUCCEEDED(ret = ACU_GetWifiStatus(&wifi)) && wifi == 0) { hidScanInput(); if (hidKeysDown() & KEY_B) { ret = -1; break; } } if (R_FAILED(ret)) { printf("Unable to access internet.\n"); return ret; } std::string outputDir = "/CIAngel"; if (titleName.length() == 0) { titleName = titleId; } // Include region in filename if (region.length() > 0) { titleName = titleName + " (" + region + ")"; } std::string mode_text; if(config.GetMode() == CConfig::Mode::DOWNLOAD_CIA) { mode_text = "create"; } else if(config.GetMode() == CConfig::Mode::INSTALL_CIA) { mode_text = "install"; } printf("Starting - %s\n", titleName.c_str()); // If in install mode, download/install the SEED entry if (config.GetMode() == CConfig::Mode::INSTALL_CIA) { // Download and install the SEEDDB entry if install mode // Code based on code from FBI: https://github.com/Steveice10/FBI/blob/master/source/core/util.c#L254 // Copyright (C) 2015 Steveice10 u8 seed[16]; static const char* regionStrings[] = {"JP", "US", "GB", "GB", "HK", "KR", "TW"}; u8 region = CFG_REGION_USA; CFGU_GetSystemLanguage(®ion); if(region <= CFG_REGION_TWN) { char url[128]; snprintf(url, 128, SEED_URL "0x%016llX/ext_key?country=%s", uTitleId, regionStrings[region]); httpcContext context; if(R_SUCCEEDED(res = httpcOpenContext(&context, HTTPC_METHOD_GET, url, 1))) { httpcSetSSLOpt(&context, SSLCOPT_DisableVerify); u32 responseCode = 0; if(R_SUCCEEDED(res = httpcBeginRequest(&context)) && R_SUCCEEDED(res = httpcGetResponseStatusCode(&context, &responseCode, 0))) { if(responseCode == 200) { u32 pos = 0; u32 bytesRead = 0; while(pos < sizeof(seed) && (R_SUCCEEDED(res = httpcDownloadData(&context, &seed[pos], sizeof(seed) - pos, &bytesRead)) || (u32)res == HTTPC_RESULTCODE_DOWNLOADPENDING)) { pos += bytesRead; } } else { res = -1; } } httpcCloseContext(&context); } if (R_SUCCEEDED(res)) { res = InstallSeed(uTitleId, seed); if (R_FAILED(res)) { printf("Error installing SEEDDB entry: 0x%lx\n", res); } } } } // Make sure the CIA doesn't already exist std::string cp = outputDir + "/" + titleName + ".cia"; if (config.GetMode() == CConfig::Mode::DOWNLOAD_CIA && FileExists(cp.c_str())) { printf("%s already exists.\n", cp.c_str()); return 0; } std::ofstream ofs; FILE *oh = fopen((outputDir + "/tmp/tmd").c_str(), "wb"); if (!oh) { printf("Error opening %s/tmp/tmd\n", outputDir.c_str()); return -1; } res = DownloadFile((NUS_URL + titleId + "/tmd").c_str(), oh, false); fclose(oh); if (res != 0) { printf("Could not download TMD. Internet/Title ID is OK?\n"); return res; } // Read version std::ifstream tmdfs; tmdfs.open(outputDir + "/tmp/tmd", std::ofstream::out | std::ofstream::in | std::ofstream::binary); char titleVersion[2]; tmdfs.seekg(top+0x9C, std::ios::beg); tmdfs.read(titleVersion, 0x2); tmdfs.close(); CreateTicket(titleId, encTitleKey, titleVersion, outputDir + "/tmp/ticket"); printf("Now %s the CIA...\n", mode_text.c_str()); res = ProcessCIA(outputDir + "/tmp", titleName); if (res != 0) { printf("Could not %s the CIA.\n", mode_text.c_str()); return res; } if (config.GetMode() == CConfig::Mode::DOWNLOAD_CIA) { rename((outputDir + "/tmp/" + titleName + ".cia").c_str(), (outputDir + "/" + titleName + ".cia").c_str()); } printf(" DONE!\n"); return res; }
static int lua_downstring(lua_State *L){ int argc = lua_gettop(L); #ifndef SKIP_ERROR_HANDLING if (argc < 1 || argc > 4) return luaL_error(L, "wrong number of arguments"); #endif const char* url = luaL_checkstring(L,1); const char* headers = (argc >= 2) ? luaL_checkstring(L,2) : NULL; u8 method = (argc >= 3) ? luaL_checkinteger(L,3) : 0; const char* postdata = (argc >= 4) ? luaL_checkstring(L,4) : NULL; httpcContext context; HTTPC_RequestMethod useMethod = HTTPC_METHOD_GET; if(method <= 3 && method >= 1) useMethod = (HTTPC_RequestMethod)method; u32 statuscode=0; do { if (statuscode >= 301 && statuscode <= 308) { char newurl[4096]; httpcGetResponseHeader(&context, (char*)"Location", &newurl[0], 4096); url = &newurl[0]; httpcCloseContext(&context); } Result ret = httpcOpenContext(&context, useMethod, (char*)url , 0); // Lets just disable SSL verification instead of loading default certs. httpcSetSSLOpt(&context, SSLCOPT_DisableVerify); if(headers != NULL){ char *tokenheader = (char*)malloc(strlen(headers)+1); strcpy(tokenheader, headers); char *toker = tokenheader; char *headername = NULL; char *headervalue = NULL; do { headername = strtok(toker, ":"); if (headername == NULL) break; headervalue = strtok(NULL, "\n"); if (headervalue == NULL) break; if (headervalue[0] == ' ') headervalue++; httpcAddRequestHeaderField(&context, headername, headervalue); toker = NULL; } while (headername != NULL && headervalue != NULL); free(tokenheader); } if (useMethod == HTTPC_METHOD_POST && postdata != NULL) { httpcAddPostDataRaw(&context, (u32*)postdata, strlen(postdata)); } #ifndef SKIP_ERROR_HANDLING if(ret==0){ #endif httpcBeginRequest(&context); long int contentsize=0; // Crash on the += if u32. WTF? u32 readSize=0; httpcGetResponseStatusCode(&context, &statuscode, 0); if (statuscode == 200) { unsigned char *buffer = (unsigned char*)malloc(0x1000); do { ret = httpcDownloadData(&context, buffer+contentsize, 0x1000, &readSize); contentsize += readSize; if (ret == (s32)HTTPC_RESULTCODE_DOWNLOADPENDING) buffer = (unsigned char*)realloc(buffer, contentsize + 0x1000); } while (ret == (s32)HTTPC_RESULTCODE_DOWNLOADPENDING); buffer = (unsigned char*)realloc(buffer, contentsize + 1); buffer[contentsize] = 0; lua_pushlstring(L,(const char*)buffer,contentsize); free(buffer); } #ifndef SKIP_ERROR_HANDLING } #endif } while ((statuscode >= 301 && statuscode <= 303) || (statuscode >= 307 && statuscode <= 308)); #ifndef SKIP_ERROR_HANDLING if ((statuscode < 200 && statuscode > 226) && statuscode != 304) luaL_error(L, "error opening url"); #endif httpcCloseContext(&context); return 1; }
static int lua_download(lua_State *L){ int argc = lua_gettop(L); #ifndef SKIP_ERROR_HANDLING if (argc < 2 || argc > 5) return luaL_error(L, "wrong number of arguments"); #endif const char* url = luaL_checkstring(L,1); const char* file = luaL_checkstring(L,2); const char* headers = (argc >= 3) ? luaL_checkstring(L,3) : NULL; u8 method = (argc >= 4) ? luaL_checkinteger(L,4) : 0; const char* postdata = (argc >= 5) ? luaL_checkstring(L,5) : NULL; httpcContext context; u32 statuscode=0; HTTPC_RequestMethod useMethod = HTTPC_METHOD_GET; if(method <= 3 && method >= 1) useMethod = (HTTPC_RequestMethod)method; do { if (statuscode >= 301 && statuscode <= 308) { char newurl[4096]; httpcGetResponseHeader(&context, (char*)"Location", &newurl[0], 4096); url = &newurl[0]; httpcCloseContext(&context); } Result ret = httpcOpenContext(&context, useMethod, (char*)url, 0); // Just disable SSL verification instead of loading default certs. httpcSetSSLOpt(&context, SSLCOPT_DisableVerify); if(headers != NULL){ char *tokenheader = (char*)malloc(strlen(headers)+1); strcpy(tokenheader, headers); char *toker = tokenheader; char *headername = NULL; char *headervalue = NULL; do { headername = strtok(toker, ":"); if (headername == NULL) break; headervalue = strtok(NULL, "\n"); if (headervalue == NULL) break; if (headervalue[0] == ' ') headervalue++; httpcAddRequestHeaderField(&context, headername, headervalue); toker = NULL; } while (headername != NULL && headervalue != NULL); free(tokenheader); } if (useMethod == HTTPC_METHOD_POST && postdata != NULL) { httpcAddPostDataRaw(&context, (u32*)postdata, strlen(postdata)); } #ifndef SKIP_ERROR_HANDLING if(ret==0){ #endif httpcBeginRequest(&context); u32 contentsize=0; httpcGetResponseStatusCode(&context, &statuscode, 0); if (statuscode == 200){ u32 readSize = 0; long int bytesWritten = 0; u8* buf = (u8*)malloc(0x1000); memset(buf, 0, 0x1000); Handle fileHandle; FS_Archive sdmcArchive=(FS_Archive){ARCHIVE_SDMC, (FS_Path){PATH_EMPTY, 1, (u8*)""}}; FS_Path filePath=fsMakePath(PATH_ASCII, file); FSUSER_OpenFileDirectly( &fileHandle, sdmcArchive, filePath, FS_OPEN_CREATE|FS_OPEN_WRITE, 0x00000000); do { ret = httpcDownloadData(&context, buf, 0x1000, &readSize); FSFILE_Write(fileHandle, NULL, bytesWritten, buf, readSize, 0x10001); bytesWritten += readSize; } while (ret == (s32)HTTPC_RESULTCODE_DOWNLOADPENDING); FSFILE_Close(fileHandle); svcCloseHandle(fileHandle); free(buf); } #ifndef SKIP_ERROR_HANDLING } #endif } while ((statuscode >= 301 && statuscode <= 303) || (statuscode >= 307 && statuscode <= 308)); #ifndef SKIP_ERROR_HANDLING if ((statuscode < 200 && statuscode > 226) && statuscode != 304) luaL_error(L, "error opening url"); #endif httpcCloseContext(&context); lua_pushinteger(L, statuscode); return 1; }