示例#1
0
nsresult
nsDOMStorage::Clear()
{
  if (!CacheStoragePermissions())
    return NS_ERROR_DOM_SECURITY_ERR;

  if (UseDB())
    CacheKeysFromDB();

  PRBool foundSecureItem = PR_FALSE;
  mItems.EnumerateEntries(CheckSecure, &foundSecureItem);

  if (foundSecureItem && !IsCallerSecure()) {
    return NS_ERROR_DOM_SECURITY_ERR;
  }

#ifdef MOZ_STORAGE
  if (UseDB()) {
    nsresult rv = InitDB();
    NS_ENSURE_SUCCESS(rv, rv);

    rv = gStorageDB->ClearStorage(this);
    NS_ENSURE_SUCCESS(rv, rv);
  }
#endif

  mItems.Clear();
  BroadcastChangeNotification();

  return NS_OK;
}
示例#2
0
NS_IMETHODIMP
nsDOMStorage::Key(PRUint32 aIndex, nsAString& aKey)
{
  // XXXjst: This is as retarded as the DOM spec is, takes an unsigned
  // int, but the spec talks about what to do if a negative value is
  // passed in.

  // XXX: This does a linear search for the key at index, which would
  // suck if there's a large numer of indexes. Do we care? If so,
  // maybe we need to have a lazily populated key array here or
  // something?

  if (!CacheStoragePermissions())
    return NS_ERROR_DOM_SECURITY_ERR;

  if (UseDB())
    CacheKeysFromDB();

  IndexFinderData data(IsCallerSecure(), aIndex);
  mItems.EnumerateEntries(IndexFinder, &data);

  if (!data.mItem) {
    // aIndex was larger than the number of accessible keys. Throw.
    return NS_ERROR_DOM_INDEX_SIZE_ERR;
  }

  aKey = data.mItem->GetKey();

  return NS_OK;
}
示例#3
0
nsresult
nsDOMStorage::GetDBValue(const nsAString& aKey, nsAString& aValue,
                         PRBool* aSecure)
{
  aValue.Truncate();

#ifdef MOZ_STORAGE
  if (!UseDB())
    return NS_OK;

  nsresult rv = InitDB();
  NS_ENSURE_SUCCESS(rv, rv);

  nsAutoString value;
  rv = gStorageDB->GetKeyValue(this, aKey, value, aSecure);

  if (rv == NS_ERROR_DOM_NOT_FOUND_ERR && mLocalStorage) {
    SetDOMStringToNull(aValue);
  }

  if (NS_FAILED(rv))
    return rv;

  if (!IsCallerSecure() && *aSecure) {
    return NS_ERROR_DOM_SECURITY_ERR;
  }

  aValue.Assign(value);
#endif

  return NS_OK;
}
示例#4
0
nsresult
nsDOMStorage::GetDBValue(const nsAString& aKey, nsAString& aValue,
                         PRBool* aSecure, nsAString& aOwner)
{
  aValue.Truncate();

#ifdef MOZ_STORAGE
  if (!UseDB())
    return NS_OK;

  nsresult rv = InitDB();
  NS_ENSURE_SUCCESS(rv, rv);

  nsAutoString value;
  rv = gStorageDB->GetKeyValue(mDomain, aKey, value, aSecure, aOwner);
  if (NS_FAILED(rv))
    return rv;

  if (!IsCallerSecure() && *aSecure) {
    return NS_ERROR_DOM_SECURITY_ERR;
  }

  aValue.Assign(value);
#endif

  return NS_OK;
}
示例#5
0
NS_IMETHODIMP
nsDOMStorage::SetItem(const nsAString& aKey, const nsAString& aData)
{
  if (!CacheStoragePermissions())
    return NS_ERROR_DOM_SECURITY_ERR;

  if (aKey.IsEmpty())
    return NS_OK;

  nsresult rv;
  nsRefPtr<nsDOMStorageItem> newitem = nsnull;
  nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
  if (entry) {
    if (entry->mItem->IsSecure() && !IsCallerSecure()) {
      return NS_ERROR_DOM_SECURITY_ERR;
    }
    if (!UseDB()) {
      entry->mItem->SetValueInternal(aData);
    }
  }
  else {
    if (UseDB())
      newitem = new nsDOMStorageItem(this, aKey, aData, PR_FALSE);
    else 
      newitem = new nsDOMStorageItem(this, aKey, aData, PR_FALSE);
    if (!newitem)
      return NS_ERROR_OUT_OF_MEMORY;
  }

  if (UseDB()) {
    rv = SetDBValue(aKey, aData, IsCallerSecure());
    NS_ENSURE_SUCCESS(rv, rv);
  }

  if (newitem) {
    entry = mItems.PutEntry(aKey);
    NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
    entry->mItem = newitem;
  }

  // SetDBValue already calls BroadcastChangeNotification so don't do it again
  if (!UseDB())
    BroadcastChangeNotification();

  return NS_OK;
}
示例#6
0
nsTArray<nsString> *
nsDOMStorage::GetKeys()
{
  if (UseDB())
    CacheKeysFromDB();

  KeysArrayBuilderStruct keystruct;
  keystruct.callerIsSecure = IsCallerSecure();
  keystruct.keys = new nsTArray<nsString>();
  if (keystruct.keys)
    mItems.EnumerateEntries(KeysArrayBuilder, &keystruct);
 
  return keystruct.keys;
}
示例#7
0
NS_IMETHODIMP nsDOMStorage::RemoveItem(const nsAString& aKey)
{
  if (!CacheStoragePermissions())
    return NS_ERROR_DOM_SECURITY_ERR;

  if (aKey.IsEmpty())
    return NS_OK;

  nsSessionStorageEntry *entry = mItems.GetEntry(aKey);

  if (entry && entry->mItem->IsSecure() && !IsCallerSecure()) {
    return NS_ERROR_DOM_SECURITY_ERR;
  }

  if (UseDB()) {
#ifdef MOZ_STORAGE
    nsresult rv = InitDB();
    NS_ENSURE_SUCCESS(rv, rv);

    nsAutoString value;
    PRBool secureItem;
    nsAutoString owner;
    rv = GetDBValue(aKey, value, &secureItem, owner);
    if (rv == NS_ERROR_DOM_NOT_FOUND_ERR)
      return NS_OK;
    NS_ENSURE_SUCCESS(rv, rv);

    rv = gStorageDB->RemoveKey(mDomain, aKey, owner,
                               aKey.Length() + value.Length());
    NS_ENSURE_SUCCESS(rv, rv);

    mItemsCached = PR_FALSE;

    BroadcastChangeNotification();
#endif
  }
  else if (entry) {
    // clear string as StorageItems may be referencing this item
    entry->mItem->ClearValue();

    BroadcastChangeNotification();
  }

  if (entry) {
    mItems.RawRemoveEntry(entry);
  }

  return NS_OK;
}
示例#8
0
NS_IMETHODIMP
nsDOMStorageItem::GetSecure(PRBool* aSecure)
{
  if (!mStorage->CacheStoragePermissions() || !IsCallerSecure()) {
    return NS_ERROR_DOM_INVALID_ACCESS_ERR;
  }

  if (mStorage->UseDB()) {
    nsAutoString value;
    return mStorage->GetDBValue(mKey, value, aSecure);
  }

  *aSecure = IsSecure();
  return NS_OK;
}
示例#9
0
NS_IMETHODIMP
nsDOMStorageItem::SetSecure(PRBool aSecure)
{
  if (!mStorage->CacheStoragePermissions() || !IsCallerSecure()) {
    return NS_ERROR_DOM_INVALID_ACCESS_ERR;
  }

  if (mStorage->UseDB()) {
    nsresult rv = mStorage->SetSecure(mKey, aSecure);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  mSecure = aSecure;
  return NS_OK;
}
示例#10
0
nsresult
nsDOMStorage::SetDBValue(const nsAString& aKey,
                         const nsAString& aValue,
                         PRBool aSecure)
{
#ifdef MOZ_STORAGE
  if (!UseDB())
    return NS_OK;

  nsresult rv = InitDB();
  NS_ENSURE_SUCCESS(rv, rv);

  // Get the current domain for quota enforcement
  nsCOMPtr<nsIPrincipal> subjectPrincipal;
  nsContentUtils::GetSecurityManager()->
    GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));

  nsAutoString currentDomain;

  if (subjectPrincipal) {
    nsCOMPtr<nsIURI> uri;
    rv = subjectPrincipal->GetURI(getter_AddRefs(uri));

    if (NS_SUCCEEDED(rv) && uri) {
      nsCAutoString currentDomainAscii;
      uri->GetAsciiHost(currentDomainAscii);
      currentDomain = NS_ConvertUTF8toUTF16(currentDomainAscii);
    }
    
    if (currentDomain.IsEmpty()) {
      return NS_ERROR_DOM_SECURITY_ERR;
    }
  } else {
    currentDomain = mDomain;
  }
  
  rv = gStorageDB->SetKey(mDomain, aKey, aValue, aSecure,
                          currentDomain, GetQuota(currentDomain));
  NS_ENSURE_SUCCESS(rv, rv);

  mItemsCached = PR_FALSE;

  BroadcastChangeNotification();
#endif

  return NS_OK;
}
示例#11
0
void
nsDOMStorage::BroadcastChangeNotification()
{
  nsresult rv;
  nsCOMPtr<nsIObserverService> observerService =
    do_GetService("@mozilla.org/observer-service;1", &rv);
  if (NS_FAILED(rv)) {
    return;
  }

  // Fire off a notification that a storage object changed. If the
  // storage object is a session storage object, we don't pass a
  // domain, but if it's a global storage object we do.
  observerService->NotifyObservers((nsIDOMStorageObsolete *)this,
                                   "dom-storage-changed",
                                   UseDB() ? NS_ConvertUTF8toUTF16(mDomain).get() : nsnull);
}
示例#12
0
NS_IMETHODIMP
nsDOMStorage::GetLength(PRUint32 *aLength)
{
  if (!CacheStoragePermissions())
    return NS_ERROR_DOM_SECURITY_ERR;

  if (UseDB())
    CacheKeysFromDB();

  ItemCounterState state(IsCallerSecure());

  mItems.EnumerateEntries(ItemCounter, &state);

  *aLength = state.mCount;

  return NS_OK;
}
示例#13
0
NS_IMETHODIMP
nsDOMStorage::GetItem(const nsAString& aKey, nsIDOMStorageItem **aItem)
{
  *aItem = nsnull;

  if (!CacheStoragePermissions())
    return NS_ERROR_DOM_SECURITY_ERR;

  if (aKey.IsEmpty())
    return NS_OK;

  nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
 
  if (entry) {
    if (!IsCallerSecure() && entry->mItem->IsSecure()) {
      return NS_OK;
    }
    NS_ADDREF(*aItem = entry->mItem);
  }
  else if (UseDB()) {
    PRBool secure;
    nsAutoString value;
    nsAutoString unused;
    nsresult rv = GetDBValue(aKey, value, &secure, unused);
    // return null if access isn't allowed or the key wasn't found
    if (rv == NS_ERROR_DOM_SECURITY_ERR || rv == NS_ERROR_DOM_NOT_FOUND_ERR)
      return NS_OK;
    NS_ENSURE_SUCCESS(rv, rv);

    nsRefPtr<nsDOMStorageItem> newitem =
      new nsDOMStorageItem(this, aKey, value, secure);
    if (!newitem)
      return NS_ERROR_OUT_OF_MEMORY;

    entry = mItems.PutEntry(aKey);
    NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);

    entry->mItem = newitem;
    NS_ADDREF(*aItem = newitem);
  }

  return NS_OK;
}
示例#14
0
nsIDOMStorageItem*
nsDOMStorage::GetNamedItem(const nsAString& aKey, nsresult* aResult)
{
  if (!CacheStoragePermissions()) {
    *aResult = NS_ERROR_DOM_SECURITY_ERR;
    return nsnull;
  }

  *aResult = NS_OK;
  if (aKey.IsEmpty())
    return nsnull;

  nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
  nsIDOMStorageItem* item = nsnull;
  if (entry) {
    if (IsCallerSecure() || !entry->mItem->IsSecure()) {
      item = entry->mItem;
    }
  }
  else if (UseDB()) {
    PRBool secure;
    nsAutoString value;
    nsresult rv = GetDBValue(aKey, value, &secure);
    // return null if access isn't allowed or the key wasn't found
    if (rv == NS_ERROR_DOM_SECURITY_ERR || rv == NS_ERROR_DOM_NOT_FOUND_ERR)
      return nsnull;

    *aResult = rv;
    NS_ENSURE_SUCCESS(rv, nsnull);

    nsRefPtr<nsDOMStorageItem> newitem =
      new nsDOMStorageItem(this, aKey, value, secure);
    if (newitem && (entry = mItems.PutEntry(aKey))) {
      item = entry->mItem = newitem;
    }
    else {
      *aResult = NS_ERROR_OUT_OF_MEMORY;
    }
  }

  return item;
}
示例#15
0
NS_IMETHODIMP
nsDOMStorage::GetLength(PRUint32 *aLength)
{
  if (!CacheStoragePermissions())
    return NS_ERROR_DOM_SECURITY_ERR;

  // Force reload of items from database.  This ensures sync localStorages for
  // same origins among different windows.
  mItemsCached = PR_FALSE;
  if (UseDB())
    CacheKeysFromDB();

  ItemCounterState state(IsCallerSecure());

  mItems.EnumerateEntries(ItemCounter, &state);

  *aLength = state.mCount;

  return NS_OK;
}
示例#16
0
NS_IMETHODIMP
nsDOMStorageItem::GetValue(nsAString& aValue)
{
  if (!mStorage->CacheStoragePermissions())
    return NS_ERROR_DOM_INVALID_ACCESS_ERR;

  if (mStorage->UseDB()) {
    // GetDBValue checks the secure state so no need to do it here
    PRBool secure;
    nsresult rv = mStorage->GetDBValue(mKey, aValue, &secure);
    if (rv == NS_ERROR_DOM_NOT_FOUND_ERR)
      return NS_OK;
    return rv;
  }

  if (IsSecure() && !IsCallerSecure()) {
    return NS_ERROR_DOM_SECURITY_ERR;
  }

  aValue = mValue;
  return NS_OK;
}
示例#17
0
nsresult
nsDOMStorage::SetSecure(const nsAString& aKey, PRBool aSecure)
{
#ifdef MOZ_STORAGE
  if (UseDB()) {
    nsresult rv = InitDB();
    NS_ENSURE_SUCCESS(rv, rv);

    return gStorageDB->SetSecure(this, aKey, aSecure);
  }
#else
  return NS_ERROR_NOT_IMPLEMENTED;
#endif

  nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
  NS_ASSERTION(entry, "Don't use SetSecure() with non-existing keys!");

  if (entry) {
    entry->mItem->SetSecureInternal(aSecure);
  }  

  return NS_OK;
}
示例#18
0
NS_IMETHODIMP
nsDOMStorageItem::SetValue(const nsAString& aValue)
{
  if (!mStorage->CacheStoragePermissions())
    return NS_ERROR_DOM_INVALID_ACCESS_ERR;

  PRBool secureCaller = IsCallerSecure();

  if (mStorage->UseDB()) {
    // SetDBValue() does the security checks for us.
    return mStorage->SetDBValue(mKey, aValue, secureCaller);
  }

  PRBool secureItem = IsSecure();

  if (!secureCaller && secureItem) {
    // The item is secure, but the caller isn't. Throw.
    return NS_ERROR_DOM_SECURITY_ERR;
  }

  mValue = aValue;
  mSecure = secureCaller;
  return NS_OK;
}
示例#19
0
nsresult
nsDOMStorage::SetDBValue(const nsAString& aKey,
                         const nsAString& aValue,
                         PRBool aSecure)
{
#ifdef MOZ_STORAGE
  if (!UseDB())
    return NS_OK;

  nsresult rv = InitDB();
  NS_ENSURE_SUCCESS(rv, rv);

  // Get the current domain for quota enforcement
  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
  if (!ssm)
    return NS_ERROR_FAILURE;

  nsCOMPtr<nsIPrincipal> subjectPrincipal;
  ssm->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));

  nsCAutoString currentDomain;

  if (subjectPrincipal) {
    nsCOMPtr<nsIURI> unused;
    rv = GetPrincipalURIAndHost(subjectPrincipal, getter_AddRefs(unused),
                                currentDomain);
    // Don't bail out on NS_ERROR_DOM_SECURITY_ERR, since we want to allow
    // trusted file:// URIs below.
    if (NS_FAILED(rv) && rv != NS_ERROR_DOM_SECURITY_ERR) {
      return rv;
    }

    if (currentDomain.IsEmpty()) {
      // allow chrome urls and trusted file urls to write using
      // the storage's domain
      if (nsContentUtils::IsCallerTrustedForWrite())
        currentDomain = mDomain;
      else
        return NS_ERROR_DOM_SECURITY_ERR;
    }
  } else {
    currentDomain = mDomain;
  }

  PRInt32 quota;
  PRInt32 warnQuota;
  GetQuota(currentDomain, &quota, &warnQuota);

  PRInt32 usage;
  rv = gStorageDB->SetKey(this, aKey, aValue, aSecure, quota, &usage);
  NS_ENSURE_SUCCESS(rv, rv);

  mItemsCached = PR_FALSE;

  if (warnQuota >= 0 && usage > warnQuota) {
    // try to include the window that exceeded the warn quota
    nsCOMPtr<nsIDOMWindow> window;
    JSContext *cx;
    nsCOMPtr<nsIJSContextStack> stack =
      do_GetService("@mozilla.org/js/xpc/ContextStack;1");
    if (stack && NS_SUCCEEDED(stack->Peek(&cx)) && cx) {
      nsCOMPtr<nsIScriptContext> scriptContext;
      scriptContext = GetScriptContextFromJSContext(cx);
      if (scriptContext) {
        window = do_QueryInterface(scriptContext->GetGlobalObject());
      }
    }

    nsCOMPtr<nsIObserverService> os =
      do_GetService("@mozilla.org/observer-service;1");
    os->NotifyObservers(window, "dom-storage-warn-quota-exceeded",
                        NS_ConvertUTF8toUTF16(currentDomain).get());
  }

  BroadcastChangeNotification();
#endif

  return NS_OK;
}