// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/modules/cookie_store/cookie_store.h"

#include <utility>

#include "base/optional.h"
#include "services/network/public/mojom/restricted_cookie_manager.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/modules/cookie_store/cookie_change_event.h"
#include "third_party/blink/renderer/modules/cookie_store/cookie_list_item.h"
#include "third_party/blink/renderer/modules/cookie_store/cookie_store_get_options.h"
#include "third_party/blink/renderer/modules/cookie_store/cookie_store_set_options.h"
#include "third_party/blink/renderer/modules/event_modules.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope.h"
#include "third_party/blink/renderer/modules/serviceworkers/service_worker_registration.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/time.h"

namespace blink {

namespace {

// Returns null if and only if an exception is thrown.
network::mojom::blink::CookieManagerGetOptionsPtr ToBackendOptions(
    const String& name,  // Value of the "name" positional argument.
    const CookieStoreGetOptions& options,
    ExceptionState& exception_state) {
  auto backend_options = network::mojom::blink::CookieManagerGetOptions::New();

  // TODO(crbug.com/729800): Handle the url option.

  if (options.matchType() == "starts-with") {
    backend_options->match_type =
        network::mojom::blink::CookieMatchType::STARTS_WITH;
  } else {
    DCHECK_EQ(options.matchType(), WTF::String("equals"));
    backend_options->match_type =
        network::mojom::blink::CookieMatchType::EQUALS;
  }

  if (name.IsNull()) {
    if (options.hasName()) {
      backend_options->name = options.name();
    } else {
      // No name provided. Use a filter that matches all cookies. This overrides
      // a user-provided matchType.
      backend_options->match_type =
          network::mojom::blink::CookieMatchType::STARTS_WITH;
      backend_options->name = g_empty_string;
    }
  } else {
    if (options.hasName()) {
      exception_state.ThrowTypeError(
          "Cookie name specified both as an argument and as an option");
      return nullptr;
    }
    backend_options->name = name;
  }

  return backend_options;
}

// Returns no value if and only if an exception is thrown.
base::Optional<WebCanonicalCookie> ToWebCanonicalCookie(
    const KURL& cookie_url,
    const String& name_arg,   // Value of the "name" positional argument.
    const String& value_arg,  // Value of the "value" positional argument.
    bool for_deletion,        // True for CookieStore.delete, false for set.
    const CookieStoreSetOptions& options,
    ExceptionState& exception_state) {
  String name;
  if (name_arg.IsNull()) {
    if (!options.hasName()) {
      exception_state.ThrowTypeError("Unspecified cookie name");
      return base::nullopt;
    }
    name = options.name();
  } else {
    if (options.hasName()) {
      exception_state.ThrowTypeError(
          "Cookie name specified both as an argument and as an option");
      return base::nullopt;
    }
    name = name_arg;
  }

  String value;
  base::Time expiry;
  if (for_deletion) {
    DCHECK(value_arg.IsNull());
    if (options.hasValue()) {
      exception_state.ThrowTypeError(
          "Cookie value is meaningless when deleting");
      return base::nullopt;
    }
    value = g_empty_string;

    if (options.hasExpires()) {
      exception_state.ThrowTypeError(
          "Cookie expiration time is meaningless when deleting");
      return base::nullopt;
    }
    expiry = WTF::Time::Min();
  } else {
    if (value_arg.IsNull()) {
      if (!options.hasValue()) {
        exception_state.ThrowTypeError("Unspecified cookie value");
        return base::nullopt;
      }
      value = options.value();
    } else {
      if (options.hasValue()) {
        exception_state.ThrowTypeError(
            "Cookie value specified both as an argument and as an option");
        return base::nullopt;
      }
      value = value_arg;
    }

    if (name.IsEmpty() && value.Contains('=')) {
      exception_state.ThrowTypeError(
          "Cookie value cannot contain '=' if the name is empty");
      return base::nullopt;
    }

    if (options.hasExpires()) {
      expiry = WTF::Time::FromJavaTime(options.expires());
    } else {
      expiry = WTF::Time();
    }
  }

  String cookie_url_host = cookie_url.Host();
  String domain;
  if (options.hasDomain()) {
    // The leading dot (".") from the domain attribute is stripped in the
    // Set-Cookie header, for compatibility. This API doesn't have compatibility
    // constraints, so reject the edge case outright.
    if (options.domain().StartsWith(".")) {
      exception_state.ThrowTypeError("Cookie domain cannot start with \".\"");
      return base::nullopt;
    }

    domain = String(".") + options.domain();
    if (!cookie_url_host.EndsWith(domain) &&
        cookie_url_host != options.domain()) {
      exception_state.ThrowTypeError(
          "Cookie domain must domain-match current host");
      return base::nullopt;
    }
  } else {
    // The absence of "domain" implies a host-only cookie.
    domain = cookie_url_host;
  }

  const String path = options.hasPath() ? options.path() : String("/");

  const bool is_secure_origin = SecurityOrigin::IsSecure(cookie_url);
  const bool secure = options.hasSecure() ? options.secure() : is_secure_origin;

  if (name.StartsWith("__Secure-") || name.StartsWith("__Host-")) {
    if (!secure) {
      exception_state.ThrowTypeError(
          "__Secure- and __Host- cookies must be secure");
      return base::nullopt;
    }
    if (!is_secure_origin) {
      exception_state.ThrowTypeError(
          "__Secure- and __Host- cookies must be written from secure origin");
      return base::nullopt;
    }
  }

  return WebCanonicalCookie::Create(
      name, value, domain, path, WTF::Time() /*creation*/, expiry,
      WTF::Time() /*last_access*/, secure, options.httpOnly(),
      WebCanonicalCookie::kDefaultSameSiteMode,
      WebCanonicalCookie::kDefaultPriority);
}

// Returns null if and only if an exception is thrown.
blink::mojom::blink::CookieChangeSubscriptionPtr ToBackendSubscription(
    const KURL& default_cookie_url,
    const CookieStoreGetOptions& subscription,
    ExceptionState& exception_state) {
  auto backend_subscription =
      blink::mojom::blink::CookieChangeSubscription::New();

  if (subscription.hasURL()) {
    KURL subscription_url(default_cookie_url, subscription.url());
    // TODO(crbug.com/729800): Check that the URL is under default_cookie_url.
    backend_subscription->url = subscription_url;
  } else {
    backend_subscription->url = default_cookie_url;
  }

  if (subscription.matchType() == "starts-with") {
    backend_subscription->match_type =
        network::mojom::blink::CookieMatchType::STARTS_WITH;
  } else {
    DCHECK_EQ(subscription.matchType(), WTF::String("equals"));
    backend_subscription->match_type =
        network::mojom::blink::CookieMatchType::EQUALS;
  }

  if (subscription.hasName()) {
    backend_subscription->name = subscription.name();
  } else {
    // No name provided. Use a filter that matches all cookies. This overrides
    // a user-provided matchType.
    backend_subscription->match_type =
        network::mojom::blink::CookieMatchType::STARTS_WITH;
    backend_subscription->name = g_empty_string;
  }

  return backend_subscription;
}

void ToCookieChangeSubscription(
    const blink::mojom::blink::CookieChangeSubscription& backend_subscription,
    CookieStoreGetOptions& subscription) {
  subscription.setURL(backend_subscription.url);

  if (backend_subscription.match_type !=
          network::mojom::blink::CookieMatchType::STARTS_WITH ||
      !backend_subscription.name.IsEmpty()) {
    subscription.setName(backend_subscription.name);
  }

  switch (backend_subscription.match_type) {
    case network::mojom::blink::CookieMatchType::STARTS_WITH:
      subscription.setMatchType(WTF::String("starts-with"));
      break;
    case network::mojom::blink::CookieMatchType::EQUALS:
      subscription.setMatchType(WTF::String("equals"));
      break;
  }

  subscription.setURL(backend_subscription.url);
}

const KURL& DefaultCookieURL(ExecutionContext* execution_context) {
  DCHECK(execution_context);

  if (execution_context->IsDocument()) {
    Document* document = ToDocument(execution_context);
    return document->CookieURL();
  }

  DCHECK(execution_context->IsServiceWorkerGlobalScope());
  ServiceWorkerGlobalScope* scope =
      ToServiceWorkerGlobalScope(execution_context);
  return scope->Url();
}

KURL DefaultSiteForCookies(ExecutionContext* execution_context) {
  DCHECK(execution_context);

  if (execution_context->IsDocument()) {
    Document* document = ToDocument(execution_context);
    return document->SiteForCookies();
  }

  DCHECK(execution_context->IsServiceWorkerGlobalScope());
  ServiceWorkerGlobalScope* scope =
      ToServiceWorkerGlobalScope(execution_context);
  return scope->Url();
}

}  // namespace

CookieStore::~CookieStore() = default;

ScriptPromise CookieStore::getAll(ScriptState* script_state,
                                  const CookieStoreGetOptions& options,
                                  ExceptionState& exception_state) {
  return getAll(script_state, WTF::String(), options, exception_state);
}

ScriptPromise CookieStore::getAll(ScriptState* script_state,
                                  const String& name,
                                  const CookieStoreGetOptions& options,
                                  ExceptionState& exception_state) {
  return DoRead(script_state, name, options,
                &CookieStore::GetAllForUrlToGetAllResult, exception_state);
}

ScriptPromise CookieStore::get(ScriptState* script_state,
                               const CookieStoreGetOptions& options,
                               ExceptionState& exception_state) {
  return get(script_state, WTF::String(), options, exception_state);
}

ScriptPromise CookieStore::get(ScriptState* script_state,
                               const String& name,
                               const CookieStoreGetOptions& options,
                               ExceptionState& exception_state) {
  return DoRead(script_state, name, options,
                &CookieStore::GetAllForUrlToGetResult, exception_state);
}

ScriptPromise CookieStore::set(ScriptState* script_state,
                               const CookieStoreSetOptions& options,
                               ExceptionState& exception_state) {
  return set(script_state, WTF::String(), WTF::String(), options,
             exception_state);
}

ScriptPromise CookieStore::set(ScriptState* script_state,
                               const String& name,
                               const String& value,
                               const CookieStoreSetOptions& options,
                               ExceptionState& exception_state) {
  return DoWrite(script_state, name, value, options, false /* is_deletion */,
                 exception_state);
}

ScriptPromise CookieStore::Delete(ScriptState* script_state,
                                  const CookieStoreSetOptions& options,
                                  ExceptionState& exception_state) {
  return Delete(script_state, WTF::String(), options, exception_state);
}

ScriptPromise CookieStore::Delete(ScriptState* script_state,
                                  const String& name,
                                  const CookieStoreSetOptions& options,
                                  ExceptionState& exception_state) {
  return DoWrite(script_state, name, WTF::String(), options,
                 true /* is_deletion */, exception_state);
}

ScriptPromise CookieStore::subscribeToChanges(
    ScriptState* script_state,
    const HeapVector<CookieStoreGetOptions>& subscriptions,
    ExceptionState& exception_state) {
  DCHECK(GetExecutionContext()->IsServiceWorkerGlobalScope());

  Vector<blink::mojom::blink::CookieChangeSubscriptionPtr>
      backend_subscriptions;
  backend_subscriptions.ReserveInitialCapacity(subscriptions.size());
  for (const CookieStoreGetOptions& subscription : subscriptions) {
    blink::mojom::blink::CookieChangeSubscriptionPtr backend_subscription =
        ToBackendSubscription(default_cookie_url_, subscription,
                              exception_state);
    if (backend_subscription.is_null()) {
      DCHECK(exception_state.HadException());
      return ScriptPromise();
    }
    backend_subscriptions.emplace_back(std::move(backend_subscription));
  }

  if (!subscription_backend_) {
    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                      "CookieStore backend went away");
    return ScriptPromise();
  }

  ServiceWorkerGlobalScope* scope =
      ToServiceWorkerGlobalScope(GetExecutionContext());

  if (!scope->IsInstalling()) {
    exception_state.ThrowTypeError("Outside the installation phase");
    return ScriptPromise();
  }

  ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
  int64_t service_worker_registration_id =
      scope->registration()->WebRegistration()->RegistrationId();
  subscription_backend_->AppendSubscriptions(
      service_worker_registration_id, std::move(backend_subscriptions),
      WTF::Bind(&CookieStore::OnSubscribeToCookieChangesResult,
                WrapPersistent(resolver)));
  return resolver->Promise();
}

ScriptPromise CookieStore::getChangeSubscriptions(
    ScriptState* script_state,
    ExceptionState& exception_state) {
  DCHECK(GetExecutionContext()->IsServiceWorkerGlobalScope());

  if (!subscription_backend_) {
    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                      "CookieStore backend went away");
    return ScriptPromise();
  }

  ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
  ServiceWorkerGlobalScope* scope =
      ToServiceWorkerGlobalScope(GetExecutionContext());
  int64_t service_worker_registration_id =
      scope->registration()->WebRegistration()->RegistrationId();
  subscription_backend_->GetSubscriptions(
      service_worker_registration_id,
      WTF::Bind(&CookieStore::OnGetCookieChangeSubscriptionResult,
                WrapPersistent(resolver)));
  return resolver->Promise();
}

void CookieStore::ContextDestroyed(ExecutionContext* execution_context) {
  StopObserving();
  backend_.reset();
}

const AtomicString& CookieStore::InterfaceName() const {
  return EventTargetNames::CookieStore;
}

ExecutionContext* CookieStore::GetExecutionContext() const {
  return ContextLifecycleObserver::GetExecutionContext();
}

void CookieStore::RemoveAllEventListeners() {
  EventTargetWithInlineData::RemoveAllEventListeners();
  DCHECK(!HasEventListeners());
  StopObserving();
}

void CookieStore::OnCookieChange(
    const WebCanonicalCookie& backend_cookie,
    network::mojom::blink::CookieChangeCause change_cause) {
  HeapVector<CookieListItem> changed, deleted;
  CookieChangeEvent::ToEventInfo(backend_cookie, change_cause, changed,
                                 deleted);
  if (changed.IsEmpty() && deleted.IsEmpty()) {
    // The backend only reported OVERWRITE events, which are dropped.
    return;
  }
  DispatchEvent(CookieChangeEvent::Create(
      EventTypeNames::change, std::move(changed), std::move(deleted)));
}

void CookieStore::AddedEventListener(
    const AtomicString& event_type,
    RegisteredEventListener& registered_listener) {
  EventTargetWithInlineData::AddedEventListener(event_type,
                                                registered_listener);
  StartObserving();
}

void CookieStore::RemovedEventListener(
    const AtomicString& event_type,
    const RegisteredEventListener& registered_listener) {
  EventTargetWithInlineData::RemovedEventListener(event_type,
                                                  registered_listener);
  if (!HasEventListeners())
    StopObserving();
}

CookieStore::CookieStore(
    ExecutionContext* execution_context,
    network::mojom::blink::RestrictedCookieManagerPtr backend,
    blink::mojom::blink::CookieStorePtr subscription_backend)
    : ContextLifecycleObserver(execution_context),
      backend_(std::move(backend)),
      subscription_backend_(std::move(subscription_backend)),
      change_listener_binding_(this),
      default_cookie_url_(DefaultCookieURL(execution_context)),
      default_site_for_cookies_(DefaultSiteForCookies(execution_context)) {
  DCHECK(backend_);
}

ScriptPromise CookieStore::DoRead(
    ScriptState* script_state,
    const String& name,
    const CookieStoreGetOptions& options,
    DoReadBackendResultConverter backend_result_converter,
    ExceptionState& exception_state) {
  network::mojom::blink::CookieManagerGetOptionsPtr backend_options =
      ToBackendOptions(name, options, exception_state);
  if (backend_options.is_null()) {
    DCHECK(exception_state.HadException());
    return ScriptPromise();
  }

  if (!backend_) {
    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                      "CookieStore backend went away");
    return ScriptPromise();
  }

  ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
  backend_->GetAllForUrl(
      default_cookie_url_, default_site_for_cookies_,
      std::move(backend_options),
      WTF::Bind(backend_result_converter, WrapPersistent(resolver)));
  return resolver->Promise();
}

// static
void CookieStore::GetAllForUrlToGetAllResult(
    ScriptPromiseResolver* resolver,
    const Vector<WebCanonicalCookie>& backend_cookies) {
  ScriptState* script_state = resolver->GetScriptState();
  if (!script_state->ContextIsValid())
    return;

  HeapVector<CookieListItem> cookies;
  cookies.ReserveInitialCapacity(backend_cookies.size());
  for (const auto& backend_cookie : backend_cookies) {
    CookieListItem& cookie = cookies.emplace_back();
    CookieChangeEvent::ToCookieListItem(backend_cookie, false /* is_deleted */,
                                        cookie);
  }

  resolver->Resolve(std::move(cookies));
}

// static
void CookieStore::GetAllForUrlToGetResult(
    ScriptPromiseResolver* resolver,
    const Vector<WebCanonicalCookie>& backend_cookies) {
  ScriptState* script_state = resolver->GetScriptState();
  if (!script_state->ContextIsValid())
    return;

  if (backend_cookies.IsEmpty()) {
    resolver->Resolve(v8::Null(script_state->GetIsolate()));
    return;
  }

  const auto& backend_cookie = backend_cookies.front();
  CookieListItem cookie;
  CookieChangeEvent::ToCookieListItem(backend_cookie, false /* is_deleted */,
                                      cookie);
  resolver->Resolve(cookie);
}

ScriptPromise CookieStore::DoWrite(ScriptState* script_state,
                                   const String& name,
                                   const String& value,
                                   const CookieStoreSetOptions& options,
                                   bool is_deletion,
                                   ExceptionState& exception_state) {
  base::Optional<WebCanonicalCookie> canonical_cookie = ToWebCanonicalCookie(
      default_cookie_url_, name, value, is_deletion, options, exception_state);
  if (!canonical_cookie) {
    DCHECK(exception_state.HadException());
    return ScriptPromise();
  }

  if (!backend_) {
    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                      "CookieStore backend went away");
    return ScriptPromise();
  }

  ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
  backend_->SetCanonicalCookie(
      std::move(canonical_cookie.value()), default_cookie_url_,
      default_site_for_cookies_,
      WTF::Bind(&CookieStore::OnSetCanonicalCookieResult,
                WrapPersistent(resolver)));
  return resolver->Promise();
}

// static
void CookieStore::OnSetCanonicalCookieResult(ScriptPromiseResolver* resolver,
                                             bool backend_success) {
  ScriptState* script_state = resolver->GetScriptState();
  if (!script_state->ContextIsValid())
    return;

  if (!backend_success) {
    resolver->Reject(DOMException::Create(
        DOMExceptionCode::kUnknownError,
        "An unknown error occured while writing the cookie."));
    return;
  }
  resolver->Resolve();
}

// static
void CookieStore::OnSubscribeToCookieChangesResult(
    ScriptPromiseResolver* resolver,
    bool backend_success) {
  ScriptState* script_state = resolver->GetScriptState();
  if (!script_state->ContextIsValid())
    return;

  if (!backend_success) {
    resolver->Reject(DOMException::Create(
        DOMExceptionCode::kUnknownError,
        "An unknown error occured while subscribing to cookie changes."));
    return;
  }
  resolver->Resolve();
}

// static
void CookieStore::OnGetCookieChangeSubscriptionResult(
    ScriptPromiseResolver* resolver,
    Vector<blink::mojom::blink::CookieChangeSubscriptionPtr> backend_result,
    bool backend_success) {
  ScriptState* script_state = resolver->GetScriptState();
  if (!script_state->ContextIsValid())
    return;

  if (!backend_success) {
    resolver->Reject(DOMException::Create(
        DOMExceptionCode::kUnknownError,
        "An unknown error occured while reading cookie change subscriptions."));
    return;
  }

  HeapVector<CookieStoreGetOptions> subscriptions;
  subscriptions.ReserveInitialCapacity(backend_result.size());
  for (const auto& backend_subscription : backend_result) {
    CookieStoreGetOptions& subscription = subscriptions.emplace_back();
    ToCookieChangeSubscription(*backend_subscription, subscription);
  }

  resolver->Resolve(std::move(subscriptions));
}

void CookieStore::StartObserving() {
  if (change_listener_binding_ || !backend_)
    return;

  network::mojom::blink::CookieChangeListenerPtr change_listener;
  change_listener_binding_.Bind(mojo::MakeRequest(&change_listener));
  backend_->AddChangeListener(default_cookie_url_, default_site_for_cookies_,
                              std::move(change_listener), {});
}

void CookieStore::StopObserving() {
  if (!change_listener_binding_.is_bound())
    return;
  change_listener_binding_.Close();
}

}  // namespace blink
