aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llviewerparcelmedia.cpp
diff options
context:
space:
mode:
authorArmin Weatherwax2011-03-13 15:19:55 +0100
committerArmin Weatherwax2011-03-13 15:19:55 +0100
commitb543f291fcf945330fd5a533cc7235c20d7cb4c5 (patch)
tree46e725a9a11f6d54535f869d0a2494efaeb6985c /linden/indra/newview/llviewerparcelmedia.cpp
parentfix voice doesn't kick in. (diff)
downloadmeta-impy-b543f291fcf945330fd5a533cc7235c20d7cb4c5.zip
meta-impy-b543f291fcf945330fd5a533cc7235c20d7cb4c5.tar.gz
meta-impy-b543f291fcf945330fd5a533cc7235c20d7cb4c5.tar.bz2
meta-impy-b543f291fcf945330fd5a533cc7235c20d7cb4c5.tar.xz
Henri Beauchamps version of Sione Lomus media filter patch.
from http://sldev.free.fr/ : "MediaFilter_v3: based on code by Sione Lomu with a couple of bugfixes by Tonya Souther, this improved patch brings media and streaming audio URLs filtering (to prevent IP ripping by so-called security systems which violate the SL TOS by catching your IP and associating your various avatars with it, thus violating your anonimity). Beside empowering your viewer with allow/deny/blacklist/whitelist functions per domain, this improved patch makes the difference between external servers (domains names filtering) and in-world servers (scripted objects with built-in HTTP servers). I also fixed various bugs, security holes and shortcomings, refactored the code and improved it, and added a whitelist/blacklist erasing function." Imprudence changes: added "MediaFilter" debug to be able to inspect the full url and media texture uuid
Diffstat (limited to 'linden/indra/newview/llviewerparcelmedia.cpp')
-rw-r--r--linden/indra/newview/llviewerparcelmedia.cpp397
1 files changed, 393 insertions, 4 deletions
diff --git a/linden/indra/newview/llviewerparcelmedia.cpp b/linden/indra/newview/llviewerparcelmedia.cpp
index d4ebbd9..a5d97f2 100644
--- a/linden/indra/newview/llviewerparcelmedia.cpp
+++ b/linden/indra/newview/llviewerparcelmedia.cpp
@@ -33,6 +33,7 @@
33#include "llviewerprecompiledheaders.h" 33#include "llviewerprecompiledheaders.h"
34#include "llviewerparcelmedia.h" 34#include "llviewerparcelmedia.h"
35 35
36#include "kokuastreamingaudio.h"
36#include "llagent.h" 37#include "llagent.h"
37#include "llviewercontrol.h" 38#include "llviewercontrol.h"
38#include "llviewermedia.h" 39#include "llviewermedia.h"
@@ -46,17 +47,27 @@
46#include "llviewerwindow.h" 47#include "llviewerwindow.h"
47#include "llfirstuse.h" 48#include "llfirstuse.h"
48#include "llpluginclassmedia.h" 49#include "llpluginclassmedia.h"
50#include "llnotify.h"
51#include "llsdserialize.h"
49 52
53#include "lloverlaybar.h"
54#include "slfloatermediafilter.h"
55#include "llinventorymodel.h"
50// Static Variables 56// Static Variables
51 57
52S32 LLViewerParcelMedia::sMediaParcelLocalID = 0; 58S32 LLViewerParcelMedia::sMediaParcelLocalID = 0;
53LLUUID LLViewerParcelMedia::sMediaRegionID; 59LLUUID LLViewerParcelMedia::sMediaRegionID;
54viewer_media_t LLViewerParcelMedia::sMediaImpl; 60viewer_media_t LLViewerParcelMedia::sMediaImpl;
55 61bool LLViewerParcelMedia::sIsUserAction = false;
62bool LLViewerParcelMedia::sMediaFilterListLoaded = false;
63LLSD LLViewerParcelMedia::sMediaFilterList;
64std::set<std::string> LLViewerParcelMedia::sMediaQueries;
65std::set<std::string> LLViewerParcelMedia::sAllowedMedia;
66std::set<std::string> LLViewerParcelMedia::sDeniedMedia;
56 67
57// Local functions 68// Local functions
58bool callback_play_media(const LLSD& notification, const LLSD& response, LLParcel* parcel); 69bool callback_play_media(const LLSD& notification, const LLSD& response, LLParcel* parcel);
59 70void callback_media_alert(const LLSD& notification, const LLSD& response, LLParcel* parcel, U32 type, std::string domain);
60 71
61// static 72// static
62void LLViewerParcelMedia::initClass() 73void LLViewerParcelMedia::initClass()
@@ -175,7 +186,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel)
175} 186}
176 187
177// static 188// static
178void LLViewerParcelMedia::play(LLParcel* parcel) 189void LLViewerParcelMedia::play(LLParcel* parcel, bool filter)
179{ 190{
180 lldebugs << "LLViewerParcelMedia::play" << llendl; 191 lldebugs << "LLViewerParcelMedia::play" << llendl;
181 192
@@ -185,7 +196,17 @@ void LLViewerParcelMedia::play(LLParcel* parcel)
185 return; 196 return;
186 197
187 std::string media_url = parcel->getMediaURL(); 198 std::string media_url = parcel->getMediaURL();
188 std::string media_current_url = parcel->getMediaCurrentURL(); 199 LLStringUtil::trim(media_url);
200
201 if (!media_url.empty() && gSavedSettings.getBOOL("MediaEnableFilter") && (filter || !allowedMedia(media_url)))
202 {
203 // If filtering is needed or in case media_url just changed
204 // to something we did not yet approve.
205 LLViewerParcelMediaAutoPlay::playStarted();
206 filterMedia(parcel, 0);
207 return;
208 }
209
189 std::string mime_type = parcel->getMediaType(); 210 std::string mime_type = parcel->getMediaType();
190 LLUUID placeholder_texture_id = parcel->getMediaID(); 211 LLUUID placeholder_texture_id = parcel->getMediaID();
191 U8 media_auto_scale = parcel->getMediaAutoScale(); 212 U8 media_auto_scale = parcel->getMediaAutoScale();
@@ -403,6 +424,8 @@ void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg, void *
403 media_url = media_url_buffer; 424 media_url = media_url_buffer;
404 msg->getU8("DataBlock", "MediaAutoScale", media_auto_scale); 425 msg->getU8("DataBlock", "MediaAutoScale", media_auto_scale);
405 426
427 LL_DEBUGS("MediaFilter") << "New media texture id: " << media_id << LL_ENDL;
428
406 if (msg->has("DataBlockExtended")) // do we have the extended data? 429 if (msg->has("DataBlockExtended")) // do we have the extended data?
407 { 430 {
408 char media_type_buffer[257]; 431 char media_type_buffer[257];
@@ -438,6 +461,7 @@ void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg, void *
438 461
439 play(parcel); 462 play(parcel);
440 } 463 }
464
441 } 465 }
442} 466}
443// Static 467// Static
@@ -586,3 +610,368 @@ void LLViewerParcelMediaNavigationObserver::onNavigateComplete( const EventType&
586 610
587} 611}
588*/ 612*/
613
614void LLViewerParcelMedia::playStreamingMusic(LLParcel* parcel, bool filter)
615{
616 std::string music_url = parcel->getMusicURL();
617 LLStringUtil::trim(music_url);
618 if (!music_url.empty() && gSavedSettings.getBOOL("MediaEnableFilter") && (filter || !allowedMedia(music_url)))
619 {
620 // If filtering is needed or in case music_url just changed
621 // to something we did not yet approve.
622 filterMedia(parcel, 1);
623 }
624 else if (gAudioStream)
625 {
626 LLStringUtil::trim(music_url);
627 gAudioStream->startInternetStream(music_url);
628 if (music_url.empty())
629 {
630 LLOverlayBar::audioFilterStop();
631 }
632 else
633 {
634 LLOverlayBar::audioFilterPlay();
635 }
636 }
637}
638
639void LLViewerParcelMedia::stopStreamingMusic()
640{
641 if (gAudioStream)
642 {
643 gAudioStream->stopInternetStream();
644 LLOverlayBar::audioFilterStop();
645 }
646}
647
648bool LLViewerParcelMedia::allowedMedia(std::string media_url)
649{
650 LLStringUtil::trim(media_url);
651 std::string domain = extractDomain(media_url);
652 if (sAllowedMedia.count(domain))
653 {
654 return true;
655 }
656 for (S32 i = 0; i < (S32)sMediaFilterList.size(); i++)
657 {
658 if (sMediaFilterList[i]["domain"].asString() == domain)
659 {
660 if (sMediaFilterList[i]["action"].asString() == "allow")
661 {
662 return true;
663 }
664 else
665 {
666 return false;
667 }
668 }
669 }
670 return false;
671}
672
673void LLViewerParcelMedia::filterMedia(LLParcel* parcel, U32 type)
674{
675 std::string media_action;
676 std::string media_url;
677 std::string domain;
678
679 if (parcel != LLViewerParcelMgr::getInstance()->getAgentParcel())
680 {
681 // The parcel just changed (may occur right out after a TP)
682 sIsUserAction = false;
683 return;
684 }
685
686 if (type == 0)
687 {
688 media_url = parcel->getMediaURL();
689 }
690 else
691 {
692 media_url = parcel->getMusicURL();
693 }
694 LLStringUtil::trim(media_url);
695
696 LL_DEBUGS("MediaFilter") << "Requested " << (type == 0 ? "media" : "music") << "-URL: " << media_url << LL_ENDL;
697
698 domain = extractDomain(media_url);
699
700 if (sMediaQueries.count(domain) > 0)
701 {
702 sIsUserAction = false;
703 return;
704 }
705
706 if (sIsUserAction)
707 {
708 // This was a user manual request to play this media, so give
709 // it another chance...
710 sIsUserAction = false;
711 if (sDeniedMedia.count(domain))
712 {
713 sDeniedMedia.erase(domain);
714 SLFloaterMediaFilter::setDirty();
715 }
716 }
717
718 if (!sMediaFilterListLoaded || sDeniedMedia.count(domain))
719 {
720 media_action = "ignore";
721 }
722 else if (sAllowedMedia.count(domain))
723 {
724 media_action = "allow";
725 }
726 else
727 {
728 for (S32 i = 0; i < (S32)sMediaFilterList.size(); i++)
729 {
730 if (sMediaFilterList[i]["domain"].asString() == domain)
731 {
732 media_action = sMediaFilterList[i]["action"].asString();
733 break;
734 }
735 }
736 }
737
738 if (media_action == "allow" || media_url.empty())
739 {
740 if (type == 0)
741 {
742 play(parcel, false);
743 }
744 else
745 {
746 playStreamingMusic(parcel, false);
747 }
748 }
749 else if (media_action == "deny")
750 {
751 LLSD args;
752 args["DOMAIN"] = domain;
753 LLNotifications::instance().add("MediaBlocked", args);
754 if (type == 1)
755 {
756 LLViewerParcelMedia::stopStreamingMusic();
757 }
758 // So to avoid other "blocked" messages later in the session
759 // for this url should it be requested again by a script.
760 sDeniedMedia.insert(domain);
761 }
762 else if (media_action == "ignore")
763 {
764 if (type == 1)
765 {
766 LLViewerParcelMedia::stopStreamingMusic();
767 }
768 }
769 else
770 {
771 sMediaQueries.insert(domain);
772 LLSD args;
773 args["DOMAIN"] = domain;
774 if (media_url.find('?') != std::string::npos)
775 {
776 args["WARNING"] = " (WARNING: this URL also contains parameter(s) that could potentially be used to correlate your avatar name with your IP)";
777 }
778 else
779 {
780 args["WARNING"] = "";
781 }
782 if (type == 0)
783 {
784 args["TYPE"] = "a media";
785 }
786 else
787 {
788 args["TYPE"] = "an audio";
789 }
790 LLNotifications::instance().add("MediaAlert", args, LLSD(), boost::bind(callback_media_alert, _1, _2, parcel, type, domain));
791 }
792}
793
794void callback_media_alert(const LLSD &notification, const LLSD &response, LLParcel* parcel, U32 type, std::string domain)
795{
796 S32 option = LLNotification::getSelectedOption(notification, response);
797
798 LLSD args;
799 args["DOMAIN"] = domain;
800
801 if (option == 0 || option == 3) // Allow or Whitelist
802 {
803 LLViewerParcelMedia::sAllowedMedia.insert(domain);
804 if (option == 3) // Whitelist
805 {
806 LLSD newmedia;
807 newmedia["domain"] = domain;
808 newmedia["action"] = "allow";
809 LLViewerParcelMedia::sMediaFilterList.append(newmedia);
810 LLViewerParcelMedia::saveDomainFilterList();
811 args["LISTED"] = "whitelisted";
812 LLNotifications::instance().add("MediaListed", args);
813 }
814 if (type == 0)
815 {
816 LLViewerParcelMedia::play(parcel, false);
817 }
818 else
819 {
820 LLViewerParcelMedia::playStreamingMusic(parcel, false);
821 }
822 }
823 else if (option == 1 || option == 2) // Deny or Blacklist
824 {
825 LLViewerParcelMedia::sDeniedMedia.insert(domain);
826 if (type == 1)
827 {
828 LLViewerParcelMedia::stopStreamingMusic();
829 }
830 if (option == 1) // Deny
831 {
832 LLNotifications::instance().add("MediaBlocked", args);
833 }
834 else // Blacklist
835 {
836 LLSD newmedia;
837 newmedia["domain"] = domain;
838 newmedia["action"] = "deny";
839 LLViewerParcelMedia::sMediaFilterList.append(newmedia);
840 LLViewerParcelMedia::saveDomainFilterList();
841 args["LISTED"] = "blacklisted";
842 LLNotifications::instance().add("MediaListed", args);
843 }
844 }
845
846 LLViewerParcelMedia::sMediaQueries.erase(domain);
847 SLFloaterMediaFilter::setDirty();
848}
849
850void LLViewerParcelMedia::saveDomainFilterList()
851{
852 std::string medialist_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "media_filter.xml");
853
854 llofstream medialistFile(medialist_filename);
855 LLSDSerialize::toPrettyXML(sMediaFilterList, medialistFile);
856 medialistFile.close();
857}
858
859bool LLViewerParcelMedia::loadDomainFilterList()
860{
861 sMediaFilterListLoaded = true;
862
863 std::string medialist_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "media_filter.xml");
864
865 if (!LLFile::isfile(medialist_filename))
866 {
867 LLSD emptyllsd;
868 llofstream medialistFile(medialist_filename);
869 LLSDSerialize::toPrettyXML(emptyllsd, medialistFile);
870 medialistFile.close();
871 }
872
873 if (LLFile::isfile(medialist_filename))
874 {
875 llifstream medialistFile(medialist_filename);
876 LLSDSerialize::fromXML(sMediaFilterList, medialistFile);
877 medialistFile.close();
878 SLFloaterMediaFilter::setDirty();
879 return true;
880 }
881 else
882 {
883 return false;
884 }
885}
886
887void LLViewerParcelMedia::clearDomainFilterList()
888{
889 sMediaFilterList.clear();
890 sAllowedMedia.clear();
891 sDeniedMedia.clear();
892 saveDomainFilterList();
893 LLNotifications::instance().add("MediaFiltersCleared");
894 SLFloaterMediaFilter::setDirty();
895}
896
897std::string LLViewerParcelMedia::extractDomain(std::string url)
898{
899 static std::string last_region = "@";
900
901 if (url.empty())
902 {
903 return url;
904 }
905
906 LLStringUtil::toLower(url);
907
908 size_t pos = url.find("//");
909
910 if (pos != std::string::npos)
911 {
912 size_t count = url.size() - pos + 2;
913 url = url.substr(pos + 2, count);
914 }
915
916 // Check that there is at least one slash in the URL and add a trailing
917 // one if not (for media/audio URLs such as http://mydomain.net)
918 if (url.find('/') == std::string::npos)
919 {
920 url += '/';
921 }
922
923 // If there's a user:password@ part, remove it
924 pos = url.find('@');
925 if (pos != std::string::npos && pos < url.find('/')) // if '@' is not before the first '/', then it's not a user:password
926 {
927 size_t count = url.size() - pos + 1;
928 url = url.substr(pos + 1, count);
929 }
930
931 if (url.find(gAgent.getRegion()->getHost().getHostName()) == 0 || url.find(last_region) == 0)
932 {
933 // This must be a scripted object rezzed in the region:
934 // extend the concept of "domain" to encompass the
935 // scripted object server id and avoid blocking all other
936 // objects at once in this region...
937
938 // Get rid of any port number
939 pos = url.find('/'); // We earlier made sure that there's one
940 url = gAgent.getRegion()->getHost().getHostName() + url.substr(pos);
941
942 pos = url.find('?');
943 if (pos != std::string::npos)
944 {
945 // Get rid of any parameter
946 url = url.substr(0, pos);
947 }
948
949 pos = url.rfind('/');
950 if (pos != std::string::npos)
951 {
952 // Get rid of the filename, if any, keeping only the server + path
953 url = url.substr(0, pos);
954 }
955 }
956 else
957 {
958 pos = url.find(':');
959 if (pos != std::string::npos && pos < url.find('/'))
960 {
961 // Keep anything before the port number and strip the rest off
962 url = url.substr(0, pos);
963 }
964 else
965 {
966 pos = url.find('/'); // We earlier made sure that there's one
967 url = url.substr(0, pos);
968 }
969 }
970
971
972 // Remember this region, so to cope with requests occuring just after a
973 // TP out of it.
974 last_region = gAgent.getRegion()->getHost().getHostName();
975
976 return url;
977}