Пример #1
0
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);
      }
   }
}
Пример #3
0
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;
}
Пример #4
0
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);
   }
}
Пример #6
0
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();
}
Пример #9
0
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();
}
Пример #10
0
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);
   }
}
Пример #11
0
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();
   }
}
Пример #13
0
/**
 * 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;
}
Пример #14
0
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;
}