OnionAliasService.cpp (2927B)
1 #include "torproject/OnionAliasService.h" 2 3 #include "mozilla/ClearOnShutdown.h" 4 #include "mozilla/StaticPrefs_browser.h" 5 #include "nsUnicharUtils.h" 6 7 /** 8 * Check if a hostname is a valid Onion v3 hostname. 9 * 10 * @param aHostname 11 * The hostname to verify. It is not a const reference because any 12 * uppercase character will be transformed to lowercase during the 13 * verification. 14 * @return Tells whether the input string is an Onion v3 address 15 */ 16 static bool ValidateOnionV3(nsACString& aHostname) { 17 constexpr nsACString::size_type v3Length = 56 + 6; 18 if (aHostname.Length() != v3Length) { 19 return false; 20 } 21 ToLowerCase(aHostname); 22 if (!StringEndsWith(aHostname, ".onion"_ns)) { 23 return false; 24 } 25 26 const char* cur = aHostname.BeginWriting(); 27 // We have already checked that it ends by ".onion" 28 const char* end = aHostname.EndWriting() - 6; 29 for (; cur < end; ++cur) { 30 if (!(islower(*cur) || ('2' <= *cur && *cur <= '7'))) { 31 return false; 32 } 33 } 34 35 return true; 36 } 37 38 namespace torproject { 39 40 NS_IMPL_ISUPPORTS(OnionAliasService, IOnionAliasService) 41 42 static mozilla::StaticRefPtr<OnionAliasService> gOAService; 43 44 // static 45 already_AddRefed<IOnionAliasService> OnionAliasService::GetSingleton() { 46 if (gOAService) { 47 return do_AddRef(gOAService); 48 } 49 50 gOAService = new OnionAliasService(); 51 ClearOnShutdown(&gOAService); 52 return do_AddRef(gOAService); 53 } 54 55 NS_IMETHODIMP 56 OnionAliasService::AddOnionAlias(const nsACString& aShortHostname, 57 const nsACString& aLongHostname) { 58 nsAutoCString shortHostname; 59 ToLowerCase(aShortHostname, shortHostname); 60 mozilla::UniquePtr<nsAutoCString> longHostname = 61 mozilla::MakeUnique<nsAutoCString>(aLongHostname); 62 if (!longHostname) { 63 return NS_ERROR_OUT_OF_MEMORY; 64 } 65 if (!StringEndsWith(shortHostname, ".tor.onion"_ns) || 66 !ValidateOnionV3(*longHostname)) { 67 return NS_ERROR_INVALID_ARG; 68 } 69 mozilla::AutoWriteLock lock(mLock); 70 mOnionAliases.InsertOrUpdate(shortHostname, std::move(longHostname)); 71 return NS_OK; 72 } 73 74 NS_IMETHODIMP 75 OnionAliasService::GetOnionAlias(const nsACString& aShortHostname, 76 nsACString& aLongHostname) { 77 aLongHostname = aShortHostname; 78 if (mozilla::StaticPrefs::browser_urlbar_onionRewrites_enabled() && 79 StringEndsWith(aShortHostname, ".tor.onion"_ns)) { 80 nsAutoCString* alias = nullptr; 81 // We want to keep the string stored in the map alive at least until we 82 // finish to copy it to the output parameter. 83 mozilla::AutoReadLock lock(mLock); 84 if (mOnionAliases.Get(aShortHostname, &alias)) { 85 // We take for granted aliases have already been validated 86 aLongHostname.Assign(*alias); 87 } 88 } 89 return NS_OK; 90 } 91 92 NS_IMETHODIMP 93 OnionAliasService::ClearOnionAliases() { 94 mozilla::AutoWriteLock lock(mLock); 95 mOnionAliases.Clear(); 96 return NS_OK; 97 } 98 99 } // namespace torproject