bool SessionManager::checkAccessControl( const char* username, InternetAddress* ip) { bool rval; // check the address against 127.x.x.x for localhost status, any user // has access control from localhost rval = (strncmp(ip->getAddress(), "127.", 4) == 0); if(!rval) { // not localhost, will have to check session database: // get bitmunk user ID Url url; url.format("/api/3.0/users?username=%s", username); DynamicObject user; if(mNode->getMessenger()->getFromBitmunk(&url, user)) { rval = mSessionDatabase.checkAccessControl( BM_USER_ID(user["id"]), ip->getAddress()); } } if(!rval) { ExceptionRef e = new Exception( "Access denied for user.", "bitmunk.webui.SessionManager.AccessDenied"); e->getDetails()["username"] = username; e->getDetails()["ip"] = ip->getAddress(); Exception::push(e); } return rval; }
void DownloadStateEventReactor::directiveCreated(Event& e) { UserId userId = BM_USER_ID(e["details"]["userId"]); const char* directiveId = e["details"]["directiveId"]->getString(); MO_CAT_DEBUG(BM_EVENTREACTOR_DS_CAT, "Event reactor handling 'directiveCreated' event for user %" PRIu64 "...", userId); // process the directive if it is of type "peerbuy": DynamicObject& directive = e["details"]["directive"]; if(strcmp(directive["type"]->getString(), "peerbuy") == 0) { Messenger* messenger = mNode->getMessenger(); Url url; url.format("%s/api/3.0/system/directives/process/%s?nodeuser=%" PRIu64, messenger->getSelfUrl(true).c_str(), directiveId, userId); DynamicObject in; if(!messenger->post(&url, NULL, &in, userId)) { // schedule exception event Event e2; e2["type"] = "bitmunk.eventreactor.EventReactor.exception"; e2["details"]["userId"] = userId; e2["details"]["exception"] = Exception::getAsDynamicObject(); mNode->getEventController()->schedule(e2); } } }
bool ControlPoint::addPortMapping(PortMapping& pm, Service& wipcs) { bool rval = true; // if internal client is not specified, get it by connecting to gateway if(!pm->hasMember("NewInternalClient") || pm["NewInternalClient"]->length() == 0) { // get the control url for the service Url url; url.format("%s%s", wipcs["rootURL"]->getString(), wipcs["controlURL"]->getString()); HttpConnectionRef conn = HttpClient::createConnection(&url); if(!conn.isNull()) { SocketAddress* addr = conn->getLocalAddress(); pm["NewInternalClient"] = addr->getAddress(); conn->close(); } else { MO_CAT_ERROR(MO_UPNP_CAT, "Could not add port mapping, could not connect to '%s'.", url.toString().c_str()); rval = false; } } if(rval) { MO_CAT_DEBUG(MO_UPNP_CAT, "Adding port mapping: %s", JsonWriter::writeToString(pm).c_str()); } // perform the action ActionResult result; rval = rval && performAction("AddPortMapping", pm, wipcs, result); if(!rval) { MO_CAT_ERROR(MO_UPNP_CAT, "Failed to add port mapping: %s, %s", JsonWriter::writeToString(pm).c_str(), JsonWriter::writeToString(Exception::getAsDynamicObject()).c_str()); } return rval; }
static bool _doReverseNetTest( Node* node, Config& cfg, UserId userId, const char* token, string& serverUrl) { bool rval = false; // start creating public server URL serverUrl = "https://"; // setup post data, use blank host to indicate to the reverse netaccess // service that our public IP should be used in the netaccess test // use a 15 seconds timeout in waiting for a response DynamicObject out; out["host"] = ""; out["port"] = cfg["port"]; out["path"] = "/api/3.0/catalog/netaccess/test"; out["sellerId"] = userId; out["token"] = token; out["timeout"] = 15; DynamicObject in; // post to bitmunk Url url; url.format("/api/3.0/catalog/netaccess/rtest"); Messenger* m = node->getMessenger(); if(m->postSecureToBitmunk(&url, &out, &in, userId)) { rval = true; serverUrl.append(in["ip"]->getString()); serverUrl.push_back(':'); serverUrl.append(cfg["port"]->getString()); // send event Event ev; ev["type"] = EVENT_NET_ACCESS_SUCCESS; ev["details"]["userId"] = userId; ev["details"]["serverUrl"] = serverUrl.c_str(); node->getEventController()->schedule(ev); } return rval; }
void DownloadStateEventReactor::postDownloadStateId( UserId userId, DownloadStateId dsId, const char* action) { Messenger* messenger = mNode->getMessenger(); Url url; url.format("%s/api/3.0/purchase/contracts/%s?nodeuser=%" PRIu64, messenger->getSelfUrl(true).c_str(), action, userId); DynamicObject out; out["downloadStateId"] = dsId; if(!messenger->post(&url, &out, NULL, userId)) { // schedule exception event Event e2; e2["type"] = "bitmunk.eventreactor.EventReactor.exception"; BM_ID_SET(e2["details"]["userId"], userId); e2["details"]["downloadStateId"] = dsId; e2["details"]["exception"] = Exception::getAsDynamicObject(); mNode->getEventController()->schedule(e2); } }
bool SampleService::getSampleRange(Media& media) { bool rval = false; // FIXME: change cache to just store sample range array? not entire media? // keep in mind that the code currently uses other information from // the media like the performer and title for the sample id3v2 tags // check with cache bool found = false; mSampleRangeCacheLock.lock(); { if(mSampleRangeCache["cache"]->hasMember(media["id"]->getString())) { media = mSampleRangeCache["cache"][media["id"]->getString()]; rval = found = true; } } mSampleRangeCacheLock.unlock(); if(!found) { // get sample range for media from bitmunk Url url; url.format("/api/3.0/media/%" PRIu64, BM_MEDIA_ID(media["id"])); StringTokenizer st; if((rval = mNode->getMessenger()->getFromBitmunk(&url, media))) { // validate sample range st.tokenize(media["sampleRange"]->getString(), '-'); if((rval = (st.getTokenCount() == 2))) { // set sample range start and end media["sampleRange"][0] = (uint32_t)strtoul(st.nextToken(), NULL, 10); media["sampleRange"][1] = (uint32_t)strtoul(st.nextToken(), NULL, 10); // update media length to use sample length int sampleLength = media["sampleRange"][1]->getUInt32() - media["sampleRange"][0]->getUInt32(); media["length"] = sampleLength; // update media title to include "- Bitmunk Sample" string title = media["title"]->getString(); title.append(" - Bitmunk Sample"); media["title"] = title.c_str(); // update cache mSampleRangeCacheLock.lock(); { if(mSampleRangeCache["cache"]->length() + 1 >= mSampleRangeCache["capacity"]->getInt32()) { // clear cache, capacity reached mSampleRangeCache->clear(); } mSampleRangeCache["cache"][media["id"]->getString()] = media; } mSampleRangeCacheLock.unlock(); } else { // no sample range available media["sampleRange"][0] = 0; media["sampleRange"][1] = 0; } // clear any sample content-length media->removeMember("sampleContentLength"); } } return rval; }
static void customCatalogTests(Node& node, TestRunner& tr) { resetTestEnvironment(node); Messenger* messenger = node.getMessenger(); // generate the ware URLs that will be used throughout the test. Url waresUrl; waresUrl.format( "%s/api/3.0/catalog/wares?nodeuser=%" PRIu64, messenger->getSelfUrl(true).c_str(), TEST_USER_ID); Url waresNonDefaultListUrl; waresNonDefaultListUrl.format( "%s/api/3.0/catalog/wares?nodeuser=%" PRIu64 "&id=%s&default=false", messenger->getSelfUrl(true).c_str(), TEST_USER_ID, TEST_WARE_ID_2); Url wareUrl; wareUrl.format( "%s/api/3.0/catalog/wares/%s?nodeuser=%" PRIu64, messenger->getSelfUrl(true).c_str(), TEST_WARE_ID_2, TEST_USER_ID); // generate the files URL that will be used to prime the medialibrary Url filesUrl; filesUrl.format("%s/api/3.2/medialibrary/files?nodeuser=%" PRIu64, messenger->getSelfUrl(true).c_str(), TEST_USER_ID); Url removeUrl; removeUrl.format( "%s/api/3.2/medialibrary/files/%s?nodeuser=%" PRIu64, messenger->getSelfUrl(true).c_str(), TEST_FILE_ID_2, TEST_USER_ID); // Create basic and detailed test ware with id=2 Ware basicWare2; Ware detailedWare2; { basicWare2["id"] = TEST_WARE_ID_2; basicWare2["description"] = "This ware was added by test-services-customcatalog"; detailedWare2 = basicWare2.clone(); detailedWare2["mediaId"] = 2; detailedWare2["fileInfos"]->setType(Array); FileInfo fi = detailedWare2["fileInfos"]->append(); fi["id"] = TEST_FILE_ID_2; fi["mediaId"] = 2; File file((sTestDataDir + TEST_FILENAME_2).c_str()); fi["extension"] = file->getExtension() + 1; fi["contentType"] = "audio/mpeg"; fi["contentSize"] = TEST_CONTENT_SIZE_2; fi["size"] = (uint64_t)file->getLength(); fi["path"] = file->getAbsolutePath(); detailedWare2["payees"]->setType(Array); Payee p1 = detailedWare2["payees"]->append(); Payee p2 = detailedWare2["payees"]->append(); p1["id"] = 900; p1["amountType"] = PAYEE_AMOUNT_TYPE_FLATFEE; p1["amount"] = "0.10"; p1["description"] = "This payee is for media ID 2"; p2["id"] = 900; p2["amountType"] = PAYEE_AMOUNT_TYPE_PTOTAL; p2["percentage"] = "0.10"; p2["description"] = "This payee is for media ID 2"; } // remove any previous files from the media library messenger->deleteResource(&removeUrl, NULL, node.getDefaultUserId()); // pass even if there is an exception - this is meant to just clear any // previous entries in the medialibrary database if they existed. Exception::clear(); tr.group("customcatalog"); tr.test("add file to medialibrary (valid)"); { DynamicObject in; DynamicObject out; // create a FileInfo object string normalizedPath; File::normalizePath( (sTestDataDir + TEST_FILENAME_2).c_str(), normalizedPath); out["path"] = normalizedPath.c_str(); out["mediaId"] = 2; // prepare event waiter EventWaiter ew(node.getEventController()); ew.start("bitmunk.medialibrary.File.updated"); ew.start("bitmunk.medialibrary.File.exception"); // add the file to the media library assertNoException( messenger->post(&filesUrl, &out, &in, node.getDefaultUserId())); // wait for file ID set event assert(ew.waitForEvent(5*1000)); // ensure it has an exception Event e = ew.popEvent(); //dumpDynamicObject(e); if(e["details"]->hasMember("exception")) { ExceptionRef ex = Exception::convertToException( e["details"]["exception"]); Exception::set(ex); } else if(strcmp( e["type"]->getString(), "bitmunk.medialibrary.File.updated") == 0) { // add new mediaLibraryId to the basic and detailed wares basicWare2["mediaLibraryId"] = e["details"]["mediaLibraryId"]; detailedWare2["mediaLibraryId"] = e["details"]["mediaLibraryId"]; } } tr.passIfNoException(); tr.test("add ware without payee-scheme (valid)"); { DynamicObject in; DynamicObject out; // create the outgoing ware object FileInfo fi; fi["id"] = TEST_FILE_ID_2; out["id"] = TEST_WARE_ID_2; out["mediaId"] = 2; out["description"] = "This ware was added by test-services-customcatalog"; out["fileInfo"] = fi; out["payees"]->setType(Array); Payee p1 = out["payees"]->append(); Payee p2 = out["payees"]->append(); p1["id"] = 900; p1["amountType"] = PAYEE_AMOUNT_TYPE_FLATFEE; p1["amount"] = "0.10"; p1["description"] = "This payee is for media ID 2"; p2["id"] = 900; p2["amountType"] = PAYEE_AMOUNT_TYPE_PTOTAL; p2["percentage"] = "0.10"; p2["description"] = "This payee is for media ID 2"; // add the ware to the custom catalog messenger->post(&waresUrl, &out, &in, node.getDefaultUserId()); // set ware payeeSchemeIds basicWare2["payeeSchemeId"] = in["payeeSchemeId"]; detailedWare2["payeeSchemeId"] = in["payeeSchemeId"]; } tr.passIfNoException(); tr.test("get ware (valid)"); { // get a specific ware from the custom catalog Ware receivedWare; assertNoException( messenger->get(&wareUrl, receivedWare, node.getDefaultUserId())); // remove format details for comparison if(receivedWare->hasMember("fileInfos") && receivedWare["fileInfos"]->getType() == Array && receivedWare["fileInfos"]->length() == 1) { receivedWare["fileInfos"][0]->removeMember("formatDetails"); } // check to make sure that the wares match assertNamedDynoCmp( "Expected ware ResourceSet", detailedWare2, "Received ware ResourceSet", receivedWare); } tr.passIfNoException(); tr.test("get wares"); { // get a specific ware from the custom catalog Ware receivedWareSet; Url url; url.format( "%s/api/3.0/catalog/wares?nodeuser=%" PRIu64 "&id=%s", messenger->getSelfUrl(true).c_str(), TEST_USER_ID, TEST_WARE_ID_2); assertNoException( messenger->get(&url, receivedWareSet, node.getDefaultUserId())); // check ware set Ware expectedWareSet; expectedWareSet["resources"][0] = basicWare2.clone(); expectedWareSet["total"] = 1; expectedWareSet["num"] = 1; expectedWareSet["start"] = 0; assertNamedDynoCmp( "Expected ware ResourceSet", expectedWareSet, "Received ware ResourceSet", receivedWareSet); } tr.passIfNoException(); tr.test("get wares by fileId"); { // get a specific ware from the custom catalog Ware receivedWareSet; Url url; url.format( "%s/api/3.0/catalog/wares?nodeuser=%" PRIu64 "&fileId=%s", messenger->getSelfUrl(true).c_str(), TEST_USER_ID, TEST_FILE_ID_2); assertNoException( messenger->get(&url, receivedWareSet, node.getDefaultUserId())); // check ware set Ware expectedWareSet; expectedWareSet["resources"][0] = basicWare2.clone(); expectedWareSet["total"] = 1; expectedWareSet["num"] = 1; expectedWareSet["start"] = 0; assertNamedDynoCmp( "Expected ware ResourceSet", expectedWareSet, "Received ware ResourceSet", receivedWareSet); } tr.passIfNoException(); tr.test("get specific unknown wares"); { // get a specific ware from the custom catalog Ware receivedWareSet; Url url; url.format( "%s/api/3.0/catalog/wares?nodeuser=%" PRIu64 "&id=%s&id=INVALID", messenger->getSelfUrl(true).c_str(), TEST_USER_ID, TEST_WARE_ID_2); messenger->get(&url, receivedWareSet, node.getDefaultUserId()); // check ware set Ware expectedWareSet; expectedWareSet["resources"][0] = basicWare2.clone(); expectedWareSet["total"] = 1; expectedWareSet["num"] = 2; expectedWareSet["start"] = 0; assertNamedDynoCmp( "Expected ware ResourceSet", expectedWareSet, "Received ware ResourceSet", receivedWareSet); } tr.passIfNoException(); tr.test("get wares by dup ware+file ids"); { // This test gets the same ware by both ware id and file id and returns // duplicate results. // get a specific ware from the custom catalog Ware receivedWareSet; Url url; url.format( "%s/api/3.0/catalog/wares?nodeuser=%" PRIu64 "&id=%s&fileId=%s", messenger->getSelfUrl(true).c_str(), TEST_USER_ID, TEST_WARE_ID_2, TEST_FILE_ID_2); messenger->get(&url, receivedWareSet, node.getDefaultUserId()); // check ware set Ware expectedWareSet; expectedWareSet["resources"][0] = basicWare2.clone(); expectedWareSet["total"] = 1; expectedWareSet["num"] = 2; expectedWareSet["start"] = 0; assertNamedDynoCmp( "Expected ware ResourceSet", expectedWareSet, "Received ware ResourceSet", receivedWareSet); } tr.passIfNoException(); tr.test("remove ware (valid)"); { // remove the ware messenger->deleteResource(&wareUrl, NULL, node.getDefaultUserId()); } tr.passIfNoException(); /*************************** Payee Scheme tests **************************/ // generate the payee schemes URL Url payeeSchemesUrl; payeeSchemesUrl.format("%s/api/3.0/catalog/payees/schemes?nodeuser=%" PRIu64, messenger->getSelfUrl(true).c_str(), TEST_USER_ID); PayeeSchemeId psId = 0; tr.test("add payee scheme (valid)"); { DynamicObject in; DynamicObject out; // create the outgoing list of payees to organize into a payee scheme out["description"] = "Payee scheme description 1"; out["payees"]->setType(Array); PayeeList payees = out["payees"]; Payee p1 = payees->append(); Payee p2 = payees->append(); p1["id"] = 900; p1["amountType"] = PAYEE_AMOUNT_TYPE_FLATFEE; p1["amount"] = "0.10"; p1["description"] = "test-services-customcatalog test payee 1"; p2["id"] = 900; p2["amountType"] = PAYEE_AMOUNT_TYPE_PTOTAL; p2["percentage"] = "0.10"; p2["description"] = "test-services-customcatalog test payee 2"; // add the ware to the custom catalog messenger->post(&payeeSchemesUrl, &out, &in, node.getDefaultUserId()); if(in->hasMember("payeeSchemeId")) { psId = in["payeeSchemeId"]->getUInt32(); } } tr.passIfNoException(); // generate the payee scheme URL Url payeeSchemeIdUrl; payeeSchemeIdUrl.format("%s/api/3.0/catalog/payees/schemes/%u?nodeuser=%" PRIu64, messenger->getSelfUrl(true).c_str(), psId, TEST_USER_ID); tr.test("get payee scheme (valid)"); { // Create the expected payee scheme PayeeScheme expectedPayeeScheme; expectedPayeeScheme["id"] = psId; expectedPayeeScheme["userId"] = node.getDefaultUserId(); expectedPayeeScheme["description"] = "Payee scheme description 1"; expectedPayeeScheme["payees"]->setType(Array); Payee p1 = expectedPayeeScheme["payees"]->append(); Payee p2 = expectedPayeeScheme["payees"]->append(); p1["id"] = 900; p1["amountType"] = PAYEE_AMOUNT_TYPE_FLATFEE; p1["amount"] = "0.10"; p1["description"] = "test-services-customcatalog test payee 1"; p2["id"] = 900; p2["amountType"] = PAYEE_AMOUNT_TYPE_PTOTAL; p2["percentage"] = "0.10"; p2["description"] = "test-services-customcatalog test payee 2"; // get a specific payee scheme from the custom catalog PayeeScheme receivedPayeeScheme; messenger->get( &payeeSchemeIdUrl, receivedPayeeScheme, node.getDefaultUserId()); // check payee schemes assertNamedDynoCmp( "Expected payee scheme", expectedPayeeScheme, "Received payee scheme", receivedPayeeScheme); } tr.passIfNoException(); tr.test("get all payee schemes (valid)"); { // Create the result set ResourceSet expectedResults; expectedResults["total"] = 2; expectedResults["start"] = 0; expectedResults["num"] = 2; PayeeScheme ps = expectedResults["resources"]->append(); ps["id"] = 1; ps["userId"] = node.getDefaultUserId(); ps["description"] = "This ware was added by test-services-customcatalog"; ps["payees"]->setType(Array); Payee p1 = ps["payees"]->append(); Payee p2 = ps["payees"]->append(); p1["id"] = 900; p1["amountType"] = PAYEE_AMOUNT_TYPE_FLATFEE; p1["amount"] = "0.10"; p1["description"] = "This payee is for media ID 2"; p2["id"] = 900; p2["amountType"] = PAYEE_AMOUNT_TYPE_PTOTAL; p2["percentage"] = "0.10"; p2["description"] = "This payee is for media ID 2"; ps = expectedResults["resources"]->append(); ps["id"] = 2; ps["userId"] = node.getDefaultUserId(); ps["description"] = "Payee scheme description 1"; ps["payees"]->setType(Array); Payee p3 = ps["payees"]->append(); Payee p4 = ps["payees"]->append(); p3["id"] = 900; p3["amountType"] = PAYEE_AMOUNT_TYPE_FLATFEE; p3["amount"] = "0.10"; p3["description"] = "test-services-customcatalog test payee 1"; p4["id"] = 900; p4["amountType"] = PAYEE_AMOUNT_TYPE_PTOTAL; p4["percentage"] = "0.10"; p4["description"] = "test-services-customcatalog test payee 2"; // get all payee schemes from the custom catalog ResourceSet receivedResults; messenger->get( &payeeSchemesUrl, receivedResults, node.getDefaultUserId()); // check payee schemes assertNamedDynoCmp( "Expected payee scheme ResourceSet", expectedResults, "Received payee scheme ResourceSet", receivedResults); } tr.passIfNoException(); tr.test("update payee scheme (valid)"); { DynamicObject in; DynamicObject out; // create the outgoing list of payees to organize into a payee scheme out["description"] = "Payee scheme description 2"; Payee p1 = out["payees"]->append(); Payee p2 = out["payees"]->append(); p1["id"] = 900; p1["amountType"] = PAYEE_AMOUNT_TYPE_FLATFEE; p1["amount"] = "0.15"; p1["description"] = "test-services-customcatalog test payee 1 (updated)"; p2["id"] = 900; p2["amountType"] = PAYEE_AMOUNT_TYPE_PTOTAL; p2["percentage"] = "0.14"; p2["description"] = "test-services-customcatalog test payee 2 (updated)"; // update a pre-existing payee scheme assertNoException( messenger->post( &payeeSchemeIdUrl, &out, &in, node.getDefaultUserId())); // ensure that the payee scheme was updated assert(in["payeeSchemeId"]->getUInt32() == 2); if(in->hasMember("payeeSchemeId")) { psId = in["payeeSchemeId"]->getUInt32(); } } tr.passIfNoException(); tr.test("add ware with payee scheme (valid)"); { DynamicObject in; DynamicObject out; // create the outgoing ware object FileInfo fi; fi["id"] = TEST_FILE_ID_2; out["id"] = TEST_WARE_ID_2; out["mediaId"] = 2; out["description"] = "This ware was added by test-services-customcatalog"; out["fileInfo"] = fi; out["payeeSchemeId"] = psId; // add the ware to the custom catalog messenger->post(&waresUrl, &out, &in, node.getDefaultUserId()); } tr.passIfNoException(); tr.test("remove associated payee scheme (invalid)"); { messenger->deleteResource( &payeeSchemeIdUrl, NULL, node.getDefaultUserId()); } tr.passIfException(); tr.test("remove ware associated w/ payee scheme (valid)"); { messenger->deleteResource( &wareUrl, NULL, node.getDefaultUserId()); } tr.passIfNoException(); tr.test("remove payee scheme (valid)"); { messenger->deleteResource( &payeeSchemeIdUrl, NULL, node.getDefaultUserId()); } tr.passIfNoException(); tr.test("create ware w/ invalid payee scheme (invalid)"); { DynamicObject in; DynamicObject out; // create the outgoing ware object FileInfo fi; fi["id"] = TEST_FILE_ID_2; PayeeScheme ps; ps["id"] = psId; out["id"] = TEST_WARE_ID_2; out["mediaId"] = 2; out["description"] = "This ware was added by test-services-customcatalog"; out["fileInfo"] = fi; out["payeeScheme"] = ps; // add the ware to the custom catalog messenger->post(&waresUrl, &out, &in, node.getDefaultUserId()); } tr.passIfException(); tr.test("remove ware (invalid)"); { // remove a ware that doesn't exist messenger->deleteResource(&wareUrl, NULL, node.getDefaultUserId()); } tr.passIfException(); tr.ungroup(); }
static void interactiveCustomCatalogTests(Node& node, TestRunner& tr) { Messenger* messenger = node.getMessenger(); tr.group("customcatalog+listing updater"); // generate the ware URLs that will be used throughout the test. Url waresUrl; waresUrl.format("%s/api/3.0/catalog/wares?nodeuser=%" PRIu64, messenger->getSelfUrl(true).c_str(), TEST_USER_ID); Url wareUrl; wareUrl.format("%s/api/3.0/catalog/wares/%s?nodeuser=%" PRIu64, messenger->getSelfUrl(true).c_str(), TEST_WARE_ID_2, TEST_USER_ID); // generate the files URL that will be used to prime the medialibrary Url filesUrl; filesUrl.format("%s/api/3.2/medialibrary/files?nodeuser=%" PRIu64, messenger->getSelfUrl(true).c_str(), TEST_USER_ID); Url removeUrl; removeUrl.format( "%s/api/3.2/medialibrary/files/%s?nodeuser=%" PRIu64, messenger->getSelfUrl(true).c_str(), TEST_FILE_ID_2, TEST_USER_ID); // remove any previous files from the media library messenger->deleteResource(&removeUrl, NULL, node.getDefaultUserId()); // pass even if there is an exception - this is meant to just clear any // previous entries in the medialibrary database if they existed. Exception::clear(); tr.test("add file to medialibrary (valid)"); { DynamicObject in; DynamicObject out; // create a FileInfo object string normalizedPath; File::normalizePath( (sTestDataDir + TEST_FILENAME_2).c_str(), normalizedPath); out["path"] = normalizedPath.c_str(); out["mediaId"] = 2; // prepare event waiter EventWaiter ew(node.getEventController()); ew.start("bitmunk.medialibrary.File.updated"); ew.start("bitmunk.medialibrary.File.exception"); // add the file to the media library assertNoException( messenger->post(&filesUrl, &out, &in, node.getDefaultUserId())); // wait for file ID set event assert(ew.waitForEvent(5*1000)); // ensure it has an exception Event e = ew.popEvent(); //dumpDynamicObject(e); if(e["details"]->hasMember("exception")) { ExceptionRef ex = Exception::convertToException( e["details"]["exception"]); Exception::set(ex); } } tr.passIfNoException(); tr.test("add ware without payee-scheme (valid)"); { DynamicObject in; DynamicObject out; // create the outgoing ware object FileInfo fi; fi["id"] = TEST_FILE_ID_2; out["id"] = TEST_WARE_ID_2; out["mediaId"] = 2; out["description"] = "This ware was added by test-services-customcatalog"; out["fileInfo"] = fi; out["payees"]->setType(Array); Payee p1 = out["payees"]->append(); Payee p2 = out["payees"]->append(); p1["id"] = 900; p1["amountType"] = PAYEE_AMOUNT_TYPE_FLATFEE; p1["amount"] = "0.10"; p1["description"] = "This payee is for media ID 2"; p2["id"] = 900; p2["amountType"] = PAYEE_AMOUNT_TYPE_PTOTAL; p2["percentage"] = "0.10"; p2["description"] = "This payee is for media ID 2"; // add the ware to the custom catalog messenger->post(&waresUrl, &out, &in, node.getDefaultUserId()); } tr.passIfNoException(); printf("\nWaiting for server info to update...\n"); Thread::sleep(2*1000); while(true) { tr.test("get server info"); { Url serverUrl; serverUrl.format("%s/api/3.0/catalog/server?nodeuser=%" PRIu64, messenger->getSelfUrl(true).c_str(), TEST_USER_ID); DynamicObject in; messenger->get(&serverUrl, in, node.getDefaultUserId()); dumpDynamicObject(in); } tr.passIfNoException(); printf( "\nSleeping to allow listing updater to run. Hit CTRL+C to quit.\n"); Thread::sleep(30*1000); } tr.ungroup(); }
static void runWebServerTest(TestRunner& tr) { const char* path = "/test"; const char* content = "web server test"; const char* regexPath = "/test/dumplings/regextest/turkey"; const char* regexPath2 = "/test/dumplings/regextest2/turkey"; const char* regexPath3 = "/test/dumplings/regextest3/turkey"; const char* regexContent = "web server test (regex)"; // create kernel Kernel k; // set thread stack size in engine (128k) k.getEngine()->getThreadPool()->setThreadStackSize(131072); // optional for testing -- // limit threads to 2: one for accepting, 1 for handling //k.getEngine()->getThreadPool()->setPoolSize(2); // start engine k.getEngine()->start(); // create server Server server; WebServer ws; Config cfg; cfg["host"] = "localhost"; cfg["port"] = 0; cfg["security"] = "off"; WebServiceContainerRef wsc = new WebServiceContainer(); ws.setContainer(wsc); ws.initialize(cfg); WebServiceRef tws = new TestWebService(path, content, regexContent); wsc->addService(tws, WebService::Both); ws.enable(&server); // start server assertNoException(server.start(&k)); // get server port int port = ws.getHostAddress()->getPort(); // check the regular path and data tr.test("WebServer - regular path handler"); { Url url; url.format("http://%s:%d%s", cfg["host"]->getString(), port, path); _checkUrlText(tr, &url, 200, content, strlen(content)); } tr.passIfNoException(); // check the regex path and data tr.test("WebServer - regex path handler"); { Url url; url.format("http://%s:%d%s", cfg["host"]->getString(), port, regexPath); _checkUrlText(tr, &url, 200, regexContent, strlen(regexContent)); } tr.passIfNoException(); // check the regex path and data tr.test("WebServer - regex path handler matches"); { DynamicObject info; info["type"] = "monarch.ws.RestfulHandler"; DynamicObject& matches = info["matches"]; matches[0] = "dumplings"; matches[1] = "turkey"; string expect = JsonWriter::writeToString(info); Url url; url.format("http://%s:%d%s", cfg["host"]->getString(), port, regexPath2); _checkUrlText(tr, &url, 200, expect.c_str(), expect.length()); } tr.passIfNoException(); // check the web service authentication exception tr.test("WebServer - authentication exception"); { DynamicObject ex; ex["message"] = "WebService authentication failed. Access denied."; ex["type"] = "monarch.ws.AccessDenied"; ex["details"]["httpStatusCode"] = 403; ex["details"]["path"] = "/test/dumplings/regextest3/turkey"; ex["details"]["public"] = true; DynamicObject& cause = ex["cause"]; cause["message"] = "Tried to authenticate but failed."; cause["type"] = "tests.ws.Exception"; string expect = JsonWriter::writeToString(ex, true); Url url; url.format("http://%s:%d%s", cfg["host"]->getString(), port, regexPath3); _checkUrlText(tr, &url, 400, expect.c_str(), expect.length()); } tr.passIfNoException(); server.stop(); // stop kernel engine k.getEngine()->stop(); }
void ListingUpdater::updateServerUrl(Seller& seller) { // get user ID UserId userId = getUserId(); MO_CAT_DEBUG(BM_CUSTOMCATALOG_CAT, "ListingUpdater testing public internet access to catalog for user %" PRIu64, userId); // create message to send after test and update DynamicObject msg; msg["testNetAccessResponse"] = true; // do net access test string serverUrl; bool pass = false; if(testNetAccess(serverUrl)) { // if server URL has NOT changed, we're done if(strcmp(seller["url"]->getString(), serverUrl.c_str()) == 0) { pass = true; MO_CAT_DEBUG(BM_CUSTOMCATALOG_CAT, "ListingUpdater net access test passed and server URL has not " "changed for user ID: %" PRIu64 ", serverUrl: '%s'", userId, serverUrl.c_str()); } // server URL has changed, post to bitmunk to update it else { MO_CAT_DEBUG(BM_CUSTOMCATALOG_CAT, "ListingUpdater net access test passed and server URL has " "changed for user ID: %" PRIu64 ", " "oldServerUrl: '%s', newServerUrl: '%s'", userId, seller["url"]->getString(), serverUrl.c_str()); DynamicObject out; out["url"] = serverUrl.c_str(); DynamicObject in; // post to bitmunk to update server URL Url url; url.format("/api/3.0/catalog/sellers/%" PRIu64 "/%" PRIu32, userId, BM_SERVER_ID(seller["serverId"])); Messenger* m = mNode->getMessenger(); if(m->postSecureToBitmunk(&url, &out, &in, userId)) { // save new server URL pass = mCatalog->setConfigValue( userId, "serverUrl", serverUrl.c_str()); } } } if(!pass) { // failed to update server URL ExceptionRef e = new Exception( "Could not test public internet access and update server URL.", "bitmunk.catalog.UpdateServerUrlError"); Exception::push(e); // log error MO_CAT_ERROR(BM_CUSTOMCATALOG_CAT, "ListingUpdater: %s", JsonWriter::writeToString(Exception::getAsDynamicObject()).c_str()); } // send message to self messageSelf(msg); // schedule a pending update request if(mUpdateRequestPending) { mUpdateRequestPending = false; DynamicObject msg; msg["updateRequest"] = true; messageSelf(msg); } }
void ListingUpdater::registerServerId() { MO_CAT_DEBUG(BM_CUSTOMCATALOG_CAT, "ListingUpdater registering for new server ID for user %" PRIu64, getUserId()); // create message to send after registration DynamicObject msg; msg["registerResponse"] = true; msg["error"] = false; // do net access test string serverUrl; bool pass = false; if(testNetAccess(serverUrl)) { DynamicObject out; out["url"] = serverUrl.c_str(); out["listingUpdateId"] = "0"; DynamicObject in; // post to bitmunk Url url; url.format("/api/3.0/catalog/sellers/%" PRIu64, getUserId()); Messenger* m = mNode->getMessenger(); if(m->postSecureToBitmunk(&url, &out, &in, getUserId())) { pass = true; // send registration data in message msg["serverId"] = in["serverId"]; msg["serverToken"] = in["serverToken"]; msg["serverUrl"] = out["url"]; } } if(!pass) { // failed to register ExceptionRef e = new Exception( "Could not register for new server ID.", "bitmunk.catalog.ServerIdRegistrationError"); Exception::push(e); DynamicObject d = Exception::getAsDynamicObject(); msg["error"] = true; msg["exception"] = d; // log error MO_CAT_ERROR(BM_CUSTOMCATALOG_CAT, "ListingUpdater: %s", JsonWriter::writeToString(d).c_str()); } // send message to self messageSelf(msg); // schedule a pending test net access request if(mTestNetAccessPending) { mTestNetAccessPending = false; DynamicObject msg; msg["testNetAccess"] = true; messageSelf(msg); } }
void DownloadStateEventReactor::reprocessRequired(Event& e) { // get user ID UserId userId = BM_USER_ID(e["details"]["userId"]); // ensure operation is done as the user to protect against logout Operation op = mNode->currentOperation(); if(mNode->addUserOperation(userId, op, NULL)) { // lock to prevent double-reprocessing download states // Note: Reprocessing the download state isn't fatal, it just may fail // silently or be annoying by re-assembling already assembled files, etc. mReprocessLock.lock(); { // log activity MO_CAT_DEBUG(BM_EVENTREACTOR_DS_CAT, "Event reactor handling ds 'reprocessRequired' " "event for user %" PRIu64 "...", userId); // get messenger Messenger* messenger = mNode->getMessenger(); // process all queued directives { Url url; url.format("%s/api/3.0/system/directives?nodeuser=%" PRIu64, messenger->getSelfUrl(true).c_str(), userId); DynamicObject directives; if(messenger->get(&url, directives, userId)) { DynamicObjectIterator i = directives.getIterator(); while(i->hasNext()) { DynamicObject& directive = i->next(); // process the directive if it is of type "peerbuy": if(strcmp(directive["type"]->getString(), "peerbuy") == 0) { url.format( "%s/api/3.0/system/directives/process/%s?nodeuser=%" PRIu64, messenger->getSelfUrl(true).c_str(), directive["id"]->getString(), userId); DynamicObject in; if(!messenger->post(&url, NULL, &in, userId)) { // schedule exception event Event e2; e2["type"] = "bitmunk.eventreactor.EventReactor.exception"; e2["details"]["exception"] = Exception::getAsDynamicObject(); mNode->getEventController()->schedule(e2); } } } } } // create a list of download states to reprocess DownloadStateList list; list->setType(Array); if(e["details"]->hasMember("all") && e["details"]["all"]->getBoolean()) { // get all non-processing download states Url url; url.format("%s/api/3.0/purchase/contracts/downloadstates" "?nodeuser=%" PRIu64 "&incomplete=true&processing=false", messenger->getSelfUrl(true).c_str(), userId); DynamicObject in; if(messenger->get(&url, in, userId)) { // append states to list list.merge(in["downloadStates"], true); } else { // schedule exception event Event e2; e2["type"] = "bitmunk.eventreactor.EventReactor.exception"; e2["details"]["exception"] = Exception::getAsDynamicObject(); mNode->getEventController()->schedule(e2); } } else if(e["details"]->hasMember("downloadStateId")) { // reprocess single download state DownloadStateId dsId = e["details"]["downloadStateId"]->getUInt64(); IPurchaseModule* ipm = dynamic_cast<IPurchaseModule*>( mNode->getKernel()->getModuleApi( "bitmunk.purchase.Purchase")); DownloadState ds; ds["id"] = dsId; BM_ID_SET(ds["userId"], userId); if(ipm->populateDownloadState(ds)) { // append state to list list->append(ds); } else { // schedule exception event Event e2; e2["type"] = "bitmunk.eventreactor.EventReactor.exception"; e2["details"]["exception"] = Exception::getAsDynamicObject(); mNode->getEventController()->schedule(e2); } } // reprocess all states in the list DynamicObjectIterator i = list.getIterator(); while(i->hasNext()) { DownloadState& ds = i->next(); DownloadStateId dsId = ds["id"]->getUInt64(); if(ds["downloadStarted"]->getBoolean()) { // do purchase only if no pieces remain if(ds["remainingPieces"]->getUInt32() == 0) { if(!ds["licensePurchased"]->getBoolean() || !ds["dataPurchased"]->getBoolean()) { // do purchase postDownloadStateId(userId, dsId, "purchase"); } else if(!ds["filesAssembled"]->getBoolean()) { // do file assembly postDownloadStateId(userId, dsId, "assemble"); } } else if(!ds["downloadPaused"]->getBoolean()) { // restart download postDownloadStateId(userId, dsId, "download"); } } else if(!ds["initialized"]->getBoolean()) { // initialize download state postDownloadStateId(userId, dsId, "initialize"); } else if(!ds["licenseAcquired"]->getBoolean()) { // acquire license postDownloadStateId(userId, dsId, "license"); } } } mReprocessLock.unlock(); } }
/** * A helper function that sends a soap envelope and gets its result. * * @param device the service to connect to. * @param service the service to use. * @param msg the soap message to send. * @param result the result to populate. * * @return true if successful, false if an exception occurred. */ static bool doSoap( Service& service, SoapMessage& msg, ActionResult& result) { bool rval = false; // create the soap envelope SoapEnvelope env; string envelope = env.create(msg); if(envelope.length() > 0) { // get the control url for the service Url url; url.format("%s%s", service["rootURL"]->getString(), service["controlURL"]->getString()); MO_CAT_DEBUG(MO_UPNP_CAT, "Sending SOAP message to url '%s':\n%s", url.toString().c_str(), envelope.c_str()); // do http connection HttpClient client; if((rval = client.connect(&url))) { // create special headers DynamicObject headers; headers["Connection"] = "close"; headers["Content-Length"] = (uint32_t)envelope.length(); headers["Content-Type"] = "text/xml; charset=\"utf-8\""; headers["Soapaction"] = StringTools::format("\"%s#%s\"", service["serviceType"]->getString(), msg["name"]->getString()).c_str(); // do post Url path(url.getPath()); ByteArrayInputStream bais(envelope.c_str(), envelope.length()); HttpResponse* response = client.post(&path, &headers, &bais); if((rval = (response != NULL))) { MO_CAT_DEBUG(MO_UPNP_CAT, "Received response header:\n%s", response->getHeader()->toString().c_str()); // receive response ByteBuffer bb(1024); ByteArrayOutputStream baos(&bb, true); if((rval = client.receiveContent(&baos))) { MO_CAT_DEBUG(MO_UPNP_CAT, "Received SOAP message:\n%s", string(bb.data(), bb.length()).c_str()); // parse soap response ByteArrayInputStream bais2(&bb); SoapResult sr; rval = env.parse(&bais2, sr); if(!rval) { // failure to parse response ExceptionRef e = new Exception( "Could not parse soap response.", "monarch.upnp.InvalidSoapResponse"); Exception::push(e); } else if(sr["fault"]->getBoolean()) { // soap fault received ExceptionRef e = new Exception( "Could not perform SOAP transfer. SOAP fault received.", "monarch.upnp.SoapFault"); e->getDetails()["fault"] = sr["message"]; Exception::set(e); rval = false; result = sr; } else { // return result as soap result result = sr; } } } // disconnect client.disconnect(); } } if(!rval) { MO_CAT_ERROR(MO_UPNP_CAT, "Could not perform SOAP transfer: %s", JsonWriter::writeToString( Exception::getAsDynamicObject()).c_str()); } return rval; }
bool ControlPoint::getServiceDescription(Service& service) { bool rval = false; // get the description url for the service Url url; url.format("%s%s", service["rootURL"]->getString(), service["SCPDURL"]->getString()); // get description string description; rval = getDescription(&url, description); if(rval) { // parse result Element root; DomReader reader; ByteArrayInputStream bais(description.c_str(), description.length()); reader.start(root); if((rval = reader.read(&bais) && reader.finish())) { MO_CAT_DEBUG(MO_UPNP_CAT, "Parsing service from xml: %s", JsonWriter::writeToString(root).c_str()); // parse out actions service["actions"]->setType(Map); if(root["children"]->hasMember("actionList")) { Element& actionList = root["children"]["actionList"][0]; if(actionList["children"]->hasMember("action")) { DynamicObjectIterator ai = actionList["children"]["action"].getIterator(); while(ai->hasNext()) { DynamicObject& action = ai->next(); // get action basics Action a; a["name"] = action["children"]["name"][0]["data"]->getString(); a["arguments"]->setType(Map); a["arguments"]["in"]->setType(Array); a["arguments"]["out"]->setType(Array); // add action arguments if(action["children"]->hasMember("argumentList")) { Element& argList = action["children"]["argumentList"][0]; DynamicObjectIterator argi = argList["children"]["argument"].getIterator(); while(argi->hasNext()) { DynamicObject& argument = argi->next(); // build argument DynamicObject name; name = argument["children"]["name"] [0]["data"]->getString(); const char* direction = argument["children"]["direction"] [0]["data"]->getString(); if(strcmp(direction, "in") == 0) { a["arguments"]["in"]->append(name); } else { a["arguments"]["out"]->append(name); } if(argument["children"]->hasMember("retval")) { a["retval"][name->getString()] = argument["children"]["retval"] [0]["data"]->getString(); } } // add action to service service["actions"][a["name"]->getString()] = a; } } } } } } if(rval) { MO_CAT_DEBUG(MO_UPNP_CAT, "Parsed service: %s", JsonWriter::writeToString(service).c_str()); } return rval; }