tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

NavigatorLogin.cpp (5255B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/dom/NavigatorLogin.h"
      8 
      9 #include "mozilla/Components.h"
     10 #include "mozilla/Maybe.h"
     11 #include "mozilla/dom/CredentialsContainer.h"
     12 #include "mozilla/dom/Document.h"
     13 #include "mozilla/dom/Promise.h"
     14 #include "mozilla/dom/WebIdentityHandler.h"
     15 #include "mozilla/net/SFVService.h"
     16 #include "nsCycleCollectionParticipant.h"
     17 #include "nsIGlobalObject.h"
     18 #include "nsIPermissionManager.h"
     19 #include "nsIPrincipal.h"
     20 #include "nsString.h"
     21 
     22 namespace mozilla {
     23 namespace dom {
     24 
     25 static constexpr nsLiteralCString kLoginStatusPermission =
     26    "self-reported-logged-in"_ns;
     27 
     28 uint32_t ConvertStatusToPermission(LoginStatus aStatus) {
     29  if (aStatus == LoginStatus::Logged_in) {
     30    return nsIPermissionManager::ALLOW_ACTION;
     31  } else if (aStatus == LoginStatus::Logged_out) {
     32    return nsIPermissionManager::DENY_ACTION;
     33  } else {
     34    // This should be unreachable, but let's return a real value
     35    return nsIPermissionManager::UNKNOWN_ACTION;
     36  }
     37 }
     38 
     39 Maybe<LoginStatus> PermissionToStatus(uint32_t aPermission) {
     40  if (aPermission == nsIPermissionManager::ALLOW_ACTION) {
     41    return Some(LoginStatus::Logged_in);
     42  } else if (aPermission == nsIPermissionManager::DENY_ACTION) {
     43    return Some(LoginStatus::Logged_out);
     44  } else {
     45    if (aPermission == nsIPermissionManager::UNKNOWN_ACTION) {
     46      MOZ_ASSERT(false, "Unexpected permission action from login status");
     47    }
     48    return Nothing();
     49  }
     50 }
     51 
     52 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(NavigatorLogin, mOwner)
     53 
     54 NavigatorLogin::~NavigatorLogin() = default;
     55 
     56 JSObject* NavigatorLogin::WrapObject(JSContext* aCx,
     57                                     JS::Handle<JSObject*> aGivenProto) {
     58  return NavigatorLogin_Binding::Wrap(aCx, this, aGivenProto);
     59 }
     60 
     61 NavigatorLogin::NavigatorLogin(nsPIDOMWindowInner* aGlobal) : mOwner(aGlobal) {
     62  MOZ_ASSERT(mOwner);
     63 };
     64 
     65 already_AddRefed<mozilla::dom::Promise> NavigatorLogin::SetStatus(
     66    LoginStatus aStatus, mozilla::ErrorResult& aRv) {
     67  RefPtr<Promise> promise = Promise::Create(mOwner->AsGlobal(), aRv);
     68  if (aRv.Failed()) {
     69    return nullptr;
     70  }
     71 
     72  if (!CredentialsContainer::IsSameOriginWithAncestors(mOwner)) {
     73    promise->MaybeRejectWithSecurityError(
     74        "navigator.login.setStatus must be called in a frame that is same-origin with its ancestors"_ns);
     75    return promise.forget();
     76  }
     77 
     78  WebIdentityHandler* identityHandler = mOwner->GetOrCreateWebIdentityHandler();
     79  if (!identityHandler) {
     80    promise->MaybeRejectWithOperationError("");
     81    return promise.forget();
     82  }
     83 
     84  identityHandler->SetLoginStatus(aStatus, promise);
     85  return promise.forget();
     86 }
     87 
     88 // static
     89 nsresult NavigatorLogin::SetLoginStatus(nsIPrincipal* aPrincipal,
     90                                        LoginStatus aStatus) {
     91  MOZ_ASSERT(XRE_IsParentProcess());
     92 
     93  nsCOMPtr<nsIPermissionManager> permMgr =
     94      components::PermissionManager::Service();
     95  if (!permMgr) {
     96    return NS_ERROR_NOT_AVAILABLE;
     97  }
     98 
     99  return permMgr->AddFromPrincipal(aPrincipal, kLoginStatusPermission,
    100                                   ConvertStatusToPermission(aStatus),
    101                                   nsIPermissionManager::EXPIRE_NEVER, 0);
    102 }
    103 
    104 // static
    105 nsresult NavigatorLogin::SetLoginStatus(nsIPrincipal* aPrincipal,
    106                                        const nsACString& aStatus) {
    107  LoginStatus parsedStatus;
    108  nsresult rv = ParseLoginStatusHeader(aStatus, parsedStatus);
    109  NS_ENSURE_SUCCESS(rv, rv);
    110  return SetLoginStatus(aPrincipal, parsedStatus);
    111 }
    112 
    113 // static
    114 nsresult NavigatorLogin::ParseLoginStatusHeader(const nsACString& aStatus,
    115                                                LoginStatus& aResult) {
    116  nsCOMPtr<nsISFVService> sfv = net::GetSFVService();
    117  nsCOMPtr<nsISFVItem> item;
    118  nsresult rv = sfv->ParseItem(aStatus, getter_AddRefs(item));
    119  if (NS_FAILED(rv)) {
    120    return rv;
    121  }
    122 
    123  nsCOMPtr<nsISFVBareItem> value;
    124  rv = item->GetValue(getter_AddRefs(value));
    125  if (NS_FAILED(rv)) {
    126    return rv;
    127  }
    128 
    129  nsCOMPtr<nsISFVToken> token = do_QueryInterface(value);
    130  if (!token) {
    131    return NS_ERROR_UNEXPECTED;
    132  }
    133 
    134  nsAutoCString parsedStatus;
    135  rv = token->GetValue(parsedStatus);
    136  if (NS_FAILED(rv)) {
    137    return rv;
    138  }
    139 
    140  if (parsedStatus == "logged-in") {
    141    aResult = LoginStatus::Logged_in;
    142    return NS_OK;
    143  }
    144  if (parsedStatus == "logged-out") {
    145    aResult = LoginStatus::Logged_out;
    146    return NS_OK;
    147  }
    148  return NS_ERROR_INVALID_ARG;
    149 }
    150 
    151 // static
    152 nsresult GetLoginStatus(nsIPrincipal* aPrincipal, Maybe<LoginStatus>& aStatus) {
    153  nsCOMPtr<nsIPermissionManager> permMgr =
    154      components::PermissionManager::Service();
    155  if (!permMgr) {
    156    aStatus = Nothing();
    157    return NS_ERROR_SERVICE_NOT_AVAILABLE;
    158  }
    159  uint32_t action;
    160  nsresult rv = permMgr->TestPermissionFromPrincipal(
    161      aPrincipal, kLoginStatusPermission, &action);
    162  if (NS_FAILED(rv)) {
    163    aStatus = Nothing();
    164    return rv;
    165  }
    166  aStatus = PermissionToStatus(action);
    167  return NS_OK;
    168 }
    169 
    170 }  // namespace dom
    171 }  // namespace mozilla