michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsCertTree.h" michael@0: michael@0: #include "pkix/pkixtypes.h" michael@0: #include "nsNSSComponent.h" // for PIPNSS string bundle calls. michael@0: #include "nsITreeColumns.h" michael@0: #include "nsIX509Cert.h" michael@0: #include "nsIX509CertValidity.h" michael@0: #include "nsIX509CertDB.h" michael@0: #include "nsXPIDLString.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsUnicharUtils.h" michael@0: #include "nsNSSCertificate.h" michael@0: #include "nsNSSCertHelper.h" michael@0: #include "nsINSSCertCache.h" michael@0: #include "nsIMutableArray.h" michael@0: #include "nsArrayUtils.h" michael@0: #include "nsISupportsPrimitives.h" michael@0: #include "nsXPCOMCID.h" michael@0: #include "nsTHashtable.h" michael@0: #include "nsHashKeys.h" michael@0: michael@0: #include "prlog.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: #ifdef PR_LOGGING michael@0: extern PRLogModuleInfo* gPIPNSSLog; michael@0: #endif michael@0: michael@0: static NS_DEFINE_CID(kCertOverrideCID, NS_CERTOVERRIDE_CID); michael@0: michael@0: // treeArrayElStr michael@0: // michael@0: // structure used to hold map of tree. Each thread (an organization michael@0: // field from a cert) has an element in the array. The numChildren field michael@0: // stores the number of certs corresponding to that thread. michael@0: struct treeArrayElStr { michael@0: nsString orgName; /* heading for thread */ michael@0: bool open; /* toggle open state for thread */ michael@0: int32_t certIndex; /* index into cert array for 1st cert */ michael@0: int32_t numChildren; /* number of chidren (certs) for thread */ michael@0: }; michael@0: michael@0: CompareCacheHashEntryPtr::CompareCacheHashEntryPtr() michael@0: { michael@0: entry = new CompareCacheHashEntry; michael@0: } michael@0: michael@0: CompareCacheHashEntryPtr::~CompareCacheHashEntryPtr() michael@0: { michael@0: delete entry; michael@0: } michael@0: michael@0: CompareCacheHashEntry::CompareCacheHashEntry() michael@0: :key(nullptr) michael@0: { michael@0: for (int i = 0; i < max_criterions; ++i) { michael@0: mCritInit[i] = false; michael@0: } michael@0: } michael@0: michael@0: static bool michael@0: CompareCacheMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr, michael@0: const void *key) michael@0: { michael@0: const CompareCacheHashEntryPtr *entryPtr = static_cast(hdr); michael@0: return entryPtr->entry->key == key; michael@0: } michael@0: michael@0: static bool michael@0: CompareCacheInitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr, michael@0: const void *key) michael@0: { michael@0: new (hdr) CompareCacheHashEntryPtr(); michael@0: CompareCacheHashEntryPtr *entryPtr = static_cast(hdr); michael@0: if (!entryPtr->entry) { michael@0: return false; michael@0: } michael@0: entryPtr->entry->key = (void*)key; michael@0: return true; michael@0: } michael@0: michael@0: static void michael@0: CompareCacheClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr) michael@0: { michael@0: CompareCacheHashEntryPtr *entryPtr = static_cast(hdr); michael@0: entryPtr->~CompareCacheHashEntryPtr(); michael@0: } michael@0: michael@0: static const PLDHashTableOps gMapOps = { michael@0: PL_DHashAllocTable, michael@0: PL_DHashFreeTable, michael@0: PL_DHashVoidPtrKeyStub, michael@0: CompareCacheMatchEntry, michael@0: PL_DHashMoveEntryStub, michael@0: CompareCacheClearEntry, michael@0: PL_DHashFinalizeStub, michael@0: CompareCacheInitEntry michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS0(nsCertAddonInfo) michael@0: NS_IMPL_ISUPPORTS(nsCertTreeDispInfo, nsICertTreeItem) michael@0: michael@0: nsCertTreeDispInfo::nsCertTreeDispInfo() michael@0: :mAddonInfo(nullptr) michael@0: ,mTypeOfEntry(direct_db) michael@0: ,mPort(-1) michael@0: ,mOverrideBits(nsCertOverride::ob_None) michael@0: ,mIsTemporary(true) michael@0: { michael@0: } michael@0: michael@0: nsCertTreeDispInfo::nsCertTreeDispInfo(nsCertTreeDispInfo &other) michael@0: { michael@0: mAddonInfo = other.mAddonInfo; michael@0: mTypeOfEntry = other.mTypeOfEntry; michael@0: mAsciiHost = other.mAsciiHost; michael@0: mPort = other.mPort; michael@0: mOverrideBits = other.mOverrideBits; michael@0: mIsTemporary = other.mIsTemporary; michael@0: mCert = other.mCert; michael@0: } michael@0: michael@0: nsCertTreeDispInfo::~nsCertTreeDispInfo() michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsCertTreeDispInfo::GetCert(nsIX509Cert **_cert) michael@0: { michael@0: NS_ENSURE_ARG(_cert); michael@0: if (mCert) { michael@0: // we may already have the cert for temporary overrides michael@0: *_cert = mCert; michael@0: NS_IF_ADDREF(*_cert); michael@0: return NS_OK; michael@0: } michael@0: if (mAddonInfo) { michael@0: *_cert = mAddonInfo->mCert.get(); michael@0: NS_IF_ADDREF(*_cert); michael@0: } michael@0: else { michael@0: *_cert = nullptr; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsCertTreeDispInfo::GetHostPort(nsAString &aHostPort) michael@0: { michael@0: nsAutoCString hostPort; michael@0: nsCertOverrideService::GetHostWithPort(mAsciiHost, mPort, hostPort); michael@0: aHostPort = NS_ConvertUTF8toUTF16(hostPort); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsCertTree, nsICertTree, nsITreeView) michael@0: michael@0: nsCertTree::nsCertTree() : mTreeArray(nullptr) michael@0: { michael@0: static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); michael@0: michael@0: mCompareCache.ops = nullptr; michael@0: mNSSComponent = do_GetService(kNSSComponentCID); michael@0: mOverrideService = do_GetService("@mozilla.org/security/certoverride;1"); michael@0: // Might be a different service if someone is overriding the contract michael@0: nsCOMPtr origCertOverride = michael@0: do_GetService(kCertOverrideCID); michael@0: mOriginalOverrideService = michael@0: static_cast(origCertOverride.get()); michael@0: mCellText = nullptr; michael@0: } michael@0: michael@0: void nsCertTree::ClearCompareHash() michael@0: { michael@0: if (mCompareCache.ops) { michael@0: PL_DHashTableFinish(&mCompareCache); michael@0: mCompareCache.ops = nullptr; michael@0: } michael@0: } michael@0: michael@0: nsresult nsCertTree::InitCompareHash() michael@0: { michael@0: ClearCompareHash(); michael@0: if (!PL_DHashTableInit(&mCompareCache, &gMapOps, nullptr, michael@0: sizeof(CompareCacheHashEntryPtr), 128, fallible_t())) { michael@0: mCompareCache.ops = nullptr; michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCertTree::~nsCertTree() michael@0: { michael@0: ClearCompareHash(); michael@0: delete [] mTreeArray; michael@0: } michael@0: michael@0: void michael@0: nsCertTree::FreeCertArray() michael@0: { michael@0: mDispInfo.Clear(); michael@0: } michael@0: michael@0: CompareCacheHashEntry * michael@0: nsCertTree::getCacheEntry(void *cache, void *aCert) michael@0: { michael@0: PLDHashTable &aCompareCache = *reinterpret_cast(cache); michael@0: CompareCacheHashEntryPtr *entryPtr = michael@0: static_cast michael@0: (PL_DHashTableOperate(&aCompareCache, aCert, PL_DHASH_ADD)); michael@0: return entryPtr ? entryPtr->entry : nullptr; michael@0: } michael@0: michael@0: void nsCertTree::RemoveCacheEntry(void *key) michael@0: { michael@0: PL_DHashTableOperate(&mCompareCache, key, PL_DHASH_REMOVE); michael@0: } michael@0: michael@0: // CountOrganizations michael@0: // michael@0: // Count the number of different organizations encountered in the cert michael@0: // list. michael@0: int32_t michael@0: nsCertTree::CountOrganizations() michael@0: { michael@0: uint32_t i, certCount; michael@0: certCount = mDispInfo.Length(); michael@0: if (certCount == 0) return 0; michael@0: nsCOMPtr orgCert = nullptr; michael@0: nsCertAddonInfo *addonInfo = mDispInfo.ElementAt(0)->mAddonInfo; michael@0: if (addonInfo) { michael@0: orgCert = addonInfo->mCert; michael@0: } michael@0: nsCOMPtr nextCert = nullptr; michael@0: int32_t orgCount = 1; michael@0: for (i=1; imAddonInfo; michael@0: if (addonInfo) { michael@0: nextCert = addonInfo->mCert; michael@0: } michael@0: // XXX we assume issuer org is always criterion 1 michael@0: if (CmpBy(&mCompareCache, orgCert, nextCert, sort_IssuerOrg, sort_None, sort_None) != 0) { michael@0: orgCert = nextCert; michael@0: orgCount++; michael@0: } michael@0: } michael@0: return orgCount; michael@0: } michael@0: michael@0: // GetThreadDescAtIndex michael@0: // michael@0: // If the row at index is an organization thread, return the collection michael@0: // associated with that thread. Otherwise, return null. michael@0: treeArrayEl * michael@0: nsCertTree::GetThreadDescAtIndex(int32_t index) michael@0: { michael@0: int i, idx=0; michael@0: if (index < 0) return nullptr; michael@0: for (i=0; i index) break; michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: // GetCertAtIndex michael@0: // michael@0: // If the row at index is a cert, return that cert. Otherwise, return null. michael@0: already_AddRefed michael@0: nsCertTree::GetCertAtIndex(int32_t index, int32_t *outAbsoluteCertOffset) michael@0: { michael@0: RefPtr certdi( michael@0: GetDispInfoAtIndex(index, outAbsoluteCertOffset)); michael@0: if (!certdi) michael@0: return nullptr; michael@0: michael@0: nsCOMPtr ret; michael@0: if (certdi->mCert) { michael@0: ret = certdi->mCert; michael@0: } else if (certdi->mAddonInfo) { michael@0: ret = certdi->mAddonInfo->mCert; michael@0: } michael@0: return ret.forget(); michael@0: } michael@0: michael@0: // If the row at index is a cert, return that cert. Otherwise, return null. michael@0: TemporaryRef michael@0: nsCertTree::GetDispInfoAtIndex(int32_t index, michael@0: int32_t *outAbsoluteCertOffset) michael@0: { michael@0: int i, idx = 0, cIndex = 0, nc; michael@0: if (index < 0) return nullptr; michael@0: // Loop over the threads michael@0: for (i=0; i certdi(mDispInfo.SafeElementAt(certIndex, michael@0: nullptr)); michael@0: if (certdi) { michael@0: return certdi.forget(); michael@0: } michael@0: break; michael@0: } michael@0: if (mTreeArray[i].open) michael@0: idx += mTreeArray[i].numChildren; michael@0: cIndex += mTreeArray[i].numChildren; michael@0: if (idx > index) break; michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: nsCertTree::nsCertCompareFunc michael@0: nsCertTree::GetCompareFuncFromCertType(uint32_t aType) michael@0: { michael@0: switch (aType) { michael@0: case nsIX509Cert2::ANY_CERT: michael@0: case nsIX509Cert::USER_CERT: michael@0: return CmpUserCert; michael@0: case nsIX509Cert::CA_CERT: michael@0: return CmpCACert; michael@0: case nsIX509Cert::EMAIL_CERT: michael@0: return CmpEmailCert; michael@0: case nsIX509Cert::SERVER_CERT: michael@0: default: michael@0: return CmpWebSiteCert; michael@0: } michael@0: } michael@0: michael@0: struct nsCertAndArrayAndPositionAndCounterAndTracker michael@0: { michael@0: RefPtr certai; michael@0: nsTArray< RefPtr > *array; michael@0: int position; michael@0: int counter; michael@0: nsTHashtable *tracker; michael@0: }; michael@0: michael@0: // Used to enumerate host:port overrides that match a stored michael@0: // certificate, creates and adds a display-info-object to the michael@0: // provided array. Increments insert position and entry counter. michael@0: // We remove the given key from the tracker, which is used to michael@0: // track entries that have not yet been handled. michael@0: // The created display-info references the cert, so make a note michael@0: // of that by incrementing the cert usage counter. michael@0: static void michael@0: MatchingCertOverridesCallback(const nsCertOverride &aSettings, michael@0: void *aUserData) michael@0: { michael@0: nsCertAndArrayAndPositionAndCounterAndTracker *cap = michael@0: (nsCertAndArrayAndPositionAndCounterAndTracker*)aUserData; michael@0: if (!cap) michael@0: return; michael@0: michael@0: nsCertTreeDispInfo *certdi = new nsCertTreeDispInfo; michael@0: if (certdi) { michael@0: if (cap->certai) michael@0: cap->certai->mUsageCount++; michael@0: certdi->mAddonInfo = cap->certai; michael@0: certdi->mTypeOfEntry = nsCertTreeDispInfo::host_port_override; michael@0: certdi->mAsciiHost = aSettings.mAsciiHost; michael@0: certdi->mPort = aSettings.mPort; michael@0: certdi->mOverrideBits = aSettings.mOverrideBits; michael@0: certdi->mIsTemporary = aSettings.mIsTemporary; michael@0: certdi->mCert = aSettings.mCert; michael@0: cap->array->InsertElementAt(cap->position, certdi); michael@0: cap->position++; michael@0: cap->counter++; michael@0: } michael@0: michael@0: // this entry is now associated to a displayed cert, remove michael@0: // it from the list of remaining entries michael@0: nsAutoCString hostPort; michael@0: nsCertOverrideService::GetHostWithPort(aSettings.mAsciiHost, aSettings.mPort, hostPort); michael@0: cap->tracker->RemoveEntry(hostPort); michael@0: } michael@0: michael@0: // Used to collect a list of the (unique) host:port keys michael@0: // for all stored overrides. michael@0: static void michael@0: CollectAllHostPortOverridesCallback(const nsCertOverride &aSettings, michael@0: void *aUserData) michael@0: { michael@0: nsTHashtable *collectorTable = michael@0: (nsTHashtable *)aUserData; michael@0: if (!collectorTable) michael@0: return; michael@0: michael@0: nsAutoCString hostPort; michael@0: nsCertOverrideService::GetHostWithPort(aSettings.mAsciiHost, aSettings.mPort, hostPort); michael@0: collectorTable->PutEntry(hostPort); michael@0: } michael@0: michael@0: struct nsArrayAndPositionAndCounterAndTracker michael@0: { michael@0: nsTArray< RefPtr > *array; michael@0: int position; michael@0: int counter; michael@0: nsTHashtable *tracker; michael@0: }; michael@0: michael@0: // Used when enumerating the stored host:port overrides where michael@0: // no associated certificate was found in the NSS database. michael@0: static void michael@0: AddRemaningHostPortOverridesCallback(const nsCertOverride &aSettings, michael@0: void *aUserData) michael@0: { michael@0: nsArrayAndPositionAndCounterAndTracker *cap = michael@0: (nsArrayAndPositionAndCounterAndTracker*)aUserData; michael@0: if (!cap) michael@0: return; michael@0: michael@0: nsAutoCString hostPort; michael@0: nsCertOverrideService::GetHostWithPort(aSettings.mAsciiHost, aSettings.mPort, hostPort); michael@0: if (!cap->tracker->GetEntry(hostPort)) michael@0: return; michael@0: michael@0: // This entry is not associated to any stored cert, michael@0: // so we still need to display it. michael@0: michael@0: nsCertTreeDispInfo *certdi = new nsCertTreeDispInfo; michael@0: if (certdi) { michael@0: certdi->mAddonInfo = nullptr; michael@0: certdi->mTypeOfEntry = nsCertTreeDispInfo::host_port_override; michael@0: certdi->mAsciiHost = aSettings.mAsciiHost; michael@0: certdi->mPort = aSettings.mPort; michael@0: certdi->mOverrideBits = aSettings.mOverrideBits; michael@0: certdi->mIsTemporary = aSettings.mIsTemporary; michael@0: certdi->mCert = aSettings.mCert; michael@0: cap->array->InsertElementAt(cap->position, certdi); michael@0: cap->position++; michael@0: cap->counter++; michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: nsCertTree::GetCertsByTypeFromCertList(CERTCertList *aCertList, michael@0: uint32_t aWantedType, michael@0: nsCertCompareFunc aCertCmpFn, michael@0: void *aCertCmpFnArg) michael@0: { michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("GetCertsByTypeFromCertList")); michael@0: if (!aCertList) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: if (!mOriginalOverrideService) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsTHashtable allHostPortOverrideKeys; michael@0: michael@0: if (aWantedType == nsIX509Cert::SERVER_CERT) { michael@0: mOriginalOverrideService-> michael@0: EnumerateCertOverrides(nullptr, michael@0: CollectAllHostPortOverridesCallback, michael@0: &allHostPortOverrideKeys); michael@0: } michael@0: michael@0: CERTCertListNode *node; michael@0: int count = 0; michael@0: for (node = CERT_LIST_HEAD(aCertList); michael@0: !CERT_LIST_END(node, aCertList); michael@0: node = CERT_LIST_NEXT(node)) { michael@0: michael@0: bool wantThisCert = (aWantedType == nsIX509Cert2::ANY_CERT); michael@0: bool wantThisCertIfNoOverrides = false; michael@0: bool wantThisCertIfHaveOverrides = false; michael@0: bool addOverrides = false; michael@0: michael@0: if (!wantThisCert) { michael@0: uint32_t thisCertType = getCertType(node->cert); michael@0: michael@0: // The output from getCertType is a "guess", which can be wrong. michael@0: // The guess is based on stored trust flags, but for the host:port michael@0: // overrides, we are storing certs without any trust flags associated. michael@0: // So we must check whether the cert really belongs to the michael@0: // server, email or unknown tab. We will lookup the cert in the override michael@0: // list to come to the decision. Unfortunately, the lookup in the michael@0: // override list is quite expensive. Therefore we are using this michael@0: // lengthy if/else statement to minimize michael@0: // the number of override-list-lookups. michael@0: michael@0: if (aWantedType == nsIX509Cert::SERVER_CERT michael@0: && thisCertType == nsIX509Cert::UNKNOWN_CERT) { michael@0: // This unknown cert was stored without trust michael@0: // Are there host:port based overrides stored? michael@0: // If yes, display them. michael@0: addOverrides = true; michael@0: } michael@0: else michael@0: if (aWantedType == nsIX509Cert::UNKNOWN_CERT michael@0: && thisCertType == nsIX509Cert::UNKNOWN_CERT) { michael@0: // This unknown cert was stored without trust. michael@0: // If there are associated overrides, do not show as unknown. michael@0: // If there are no associated overrides, display as unknown. michael@0: wantThisCertIfNoOverrides = true; michael@0: } michael@0: else michael@0: if (aWantedType == nsIX509Cert::SERVER_CERT michael@0: && thisCertType == nsIX509Cert::SERVER_CERT) { michael@0: // This server cert is explicitly marked as a web site peer, michael@0: // with or without trust, but editable, so show it michael@0: wantThisCert = true; michael@0: // Are there host:port based overrides stored? michael@0: // If yes, display them. michael@0: addOverrides = true; michael@0: } michael@0: else michael@0: if (aWantedType == nsIX509Cert::SERVER_CERT michael@0: && thisCertType == nsIX509Cert::EMAIL_CERT) { michael@0: // This cert might have been categorized as an email cert michael@0: // because it carries an email address. But is it really one? michael@0: // Our cert categorization is uncertain when it comes to michael@0: // distinguish between email certs and web site certs. michael@0: // So, let's see if we have an override for that cert michael@0: // and if there is, conclude it's really a web site cert. michael@0: addOverrides = true; michael@0: } michael@0: else michael@0: if (aWantedType == nsIX509Cert::EMAIL_CERT michael@0: && thisCertType == nsIX509Cert::EMAIL_CERT) { michael@0: // This cert might have been categorized as an email cert michael@0: // because it carries an email address. But is it really one? michael@0: // Our cert categorization is uncertain when it comes to michael@0: // distinguish between email certs and web site certs. michael@0: // So, let's see if we have an override for that cert michael@0: // and if there is, conclude it's really a web site cert. michael@0: wantThisCertIfNoOverrides = true; michael@0: } michael@0: else michael@0: if (thisCertType == aWantedType) { michael@0: wantThisCert = true; michael@0: } michael@0: } michael@0: michael@0: nsCOMPtr pipCert = nsNSSCertificate::Create(node->cert); michael@0: if (!pipCert) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: if (wantThisCertIfNoOverrides || wantThisCertIfHaveOverrides) { michael@0: uint32_t ocount = 0; michael@0: nsresult rv = michael@0: mOverrideService->IsCertUsedForOverrides(pipCert, michael@0: true, // we want temporaries michael@0: true, // we want permanents michael@0: &ocount); michael@0: if (wantThisCertIfNoOverrides) { michael@0: if (NS_FAILED(rv) || ocount == 0) { michael@0: // no overrides for this cert michael@0: wantThisCert = true; michael@0: } michael@0: } michael@0: michael@0: if (wantThisCertIfHaveOverrides) { michael@0: if (NS_SUCCEEDED(rv) && ocount > 0) { michael@0: // there are overrides for this cert michael@0: wantThisCert = true; michael@0: } michael@0: } michael@0: } michael@0: michael@0: RefPtr certai(new nsCertAddonInfo); michael@0: certai->mCert = pipCert; michael@0: certai->mUsageCount = 0; michael@0: michael@0: if (wantThisCert || addOverrides) { michael@0: int InsertPosition = 0; michael@0: for (; InsertPosition < count; ++InsertPosition) { michael@0: nsCOMPtr cert = nullptr; michael@0: RefPtr elem( michael@0: mDispInfo.SafeElementAt(InsertPosition, nullptr)); michael@0: if (elem && elem->mAddonInfo) { michael@0: cert = elem->mAddonInfo->mCert; michael@0: } michael@0: if ((*aCertCmpFn)(aCertCmpFnArg, pipCert, cert) < 0) { michael@0: break; michael@0: } michael@0: } michael@0: if (wantThisCert) { michael@0: nsCertTreeDispInfo *certdi = new nsCertTreeDispInfo; michael@0: certdi->mAddonInfo = certai; michael@0: certai->mUsageCount++; michael@0: certdi->mTypeOfEntry = nsCertTreeDispInfo::direct_db; michael@0: // not necessary: certdi->mAsciiHost.Clear(); certdi->mPort = -1; michael@0: certdi->mOverrideBits = nsCertOverride::ob_None; michael@0: certdi->mIsTemporary = false; michael@0: mDispInfo.InsertElementAt(InsertPosition, certdi); michael@0: ++count; michael@0: ++InsertPosition; michael@0: } michael@0: if (addOverrides) { michael@0: nsCertAndArrayAndPositionAndCounterAndTracker cap; michael@0: cap.certai = certai; michael@0: cap.array = &mDispInfo; michael@0: cap.position = InsertPosition; michael@0: cap.counter = 0; michael@0: cap.tracker = &allHostPortOverrideKeys; michael@0: michael@0: mOriginalOverrideService-> michael@0: EnumerateCertOverrides(pipCert, MatchingCertOverridesCallback, &cap); michael@0: count += cap.counter; michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (aWantedType == nsIX509Cert::SERVER_CERT) { michael@0: nsArrayAndPositionAndCounterAndTracker cap; michael@0: cap.array = &mDispInfo; michael@0: cap.position = 0; michael@0: cap.counter = 0; michael@0: cap.tracker = &allHostPortOverrideKeys; michael@0: mOriginalOverrideService-> michael@0: EnumerateCertOverrides(nullptr, AddRemaningHostPortOverridesCallback, &cap); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsCertTree::GetCertsByType(uint32_t aType, michael@0: nsCertCompareFunc aCertCmpFn, michael@0: void *aCertCmpFnArg) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: nsCOMPtr cxt = new PipUIContext(); michael@0: mozilla::pkix::ScopedCERTCertList certList( michael@0: PK11_ListCerts(PK11CertListUnique, cxt)); michael@0: return GetCertsByTypeFromCertList(certList.get(), aType, aCertCmpFn, michael@0: aCertCmpFnArg); michael@0: } michael@0: michael@0: nsresult michael@0: nsCertTree::GetCertsByTypeFromCache(nsINSSCertCache *aCache, michael@0: uint32_t aType, michael@0: nsCertCompareFunc aCertCmpFn, michael@0: void *aCertCmpFnArg) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aCache); michael@0: CERTCertList *certList = reinterpret_cast(aCache->GetCachedCerts()); michael@0: if (!certList) michael@0: return NS_ERROR_FAILURE; michael@0: return GetCertsByTypeFromCertList(certList, aType, aCertCmpFn, aCertCmpFnArg); michael@0: } michael@0: michael@0: // LoadCerts michael@0: // michael@0: // Load all of the certificates in the DB for this type. Sort them michael@0: // by token, organization, then common name. michael@0: NS_IMETHODIMP michael@0: nsCertTree::LoadCertsFromCache(nsINSSCertCache *aCache, uint32_t aType) michael@0: { michael@0: if (mTreeArray) { michael@0: FreeCertArray(); michael@0: delete [] mTreeArray; michael@0: mTreeArray = nullptr; michael@0: mNumRows = 0; michael@0: } michael@0: nsresult rv = InitCompareHash(); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = GetCertsByTypeFromCache(aCache, aType, michael@0: GetCompareFuncFromCertType(aType), &mCompareCache); michael@0: if (NS_FAILED(rv)) return rv; michael@0: return UpdateUIContents(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsCertTree::LoadCerts(uint32_t aType) michael@0: { michael@0: if (mTreeArray) { michael@0: FreeCertArray(); michael@0: delete [] mTreeArray; michael@0: mTreeArray = nullptr; michael@0: mNumRows = 0; michael@0: } michael@0: nsresult rv = InitCompareHash(); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = GetCertsByType(aType, michael@0: GetCompareFuncFromCertType(aType), &mCompareCache); michael@0: if (NS_FAILED(rv)) return rv; michael@0: return UpdateUIContents(); michael@0: } michael@0: michael@0: nsresult michael@0: nsCertTree::UpdateUIContents() michael@0: { michael@0: uint32_t count = mDispInfo.Length(); michael@0: mNumOrgs = CountOrganizations(); michael@0: mTreeArray = new treeArrayEl[mNumOrgs]; michael@0: michael@0: mCellText = do_CreateInstance(NS_ARRAY_CONTRACTID); michael@0: michael@0: if (count) { michael@0: uint32_t j = 0; michael@0: nsCOMPtr orgCert = nullptr; michael@0: nsCertAddonInfo *addonInfo = mDispInfo.ElementAt(j)->mAddonInfo; michael@0: if (addonInfo) { michael@0: orgCert = addonInfo->mCert; michael@0: } michael@0: for (int32_t i=0; iGetPIPNSSBundleString("CertOrgUnknown", orgNameRef); michael@0: } michael@0: else { michael@0: orgCert->GetIssuerOrganization(orgNameRef); michael@0: if (orgNameRef.IsEmpty()) michael@0: orgCert->GetCommonName(orgNameRef); michael@0: } michael@0: mTreeArray[i].open = true; michael@0: mTreeArray[i].certIndex = j; michael@0: mTreeArray[i].numChildren = 1; michael@0: if (++j >= count) break; michael@0: nsCOMPtr nextCert = nullptr; michael@0: nsCertAddonInfo *addonInfo = mDispInfo.SafeElementAt(j, nullptr)->mAddonInfo; michael@0: if (addonInfo) { michael@0: nextCert = addonInfo->mCert; michael@0: } michael@0: while (0 == CmpBy(&mCompareCache, orgCert, nextCert, sort_IssuerOrg, sort_None, sort_None)) { michael@0: mTreeArray[i].numChildren++; michael@0: if (++j >= count) break; michael@0: nextCert = nullptr; michael@0: addonInfo = mDispInfo.SafeElementAt(j, nullptr)->mAddonInfo; michael@0: if (addonInfo) { michael@0: nextCert = addonInfo->mCert; michael@0: } michael@0: } michael@0: orgCert = nextCert; michael@0: } michael@0: } michael@0: if (mTree) { michael@0: mTree->BeginUpdateBatch(); michael@0: mTree->RowCountChanged(0, -mNumRows); michael@0: } michael@0: mNumRows = count + mNumOrgs; michael@0: if (mTree) michael@0: mTree->EndUpdateBatch(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsCertTree::DeleteEntryObject(uint32_t index) michael@0: { michael@0: if (!mTreeArray) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsCOMPtr certdb = michael@0: do_GetService("@mozilla.org/security/x509certdb;1"); michael@0: if (!certdb) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: int i; michael@0: uint32_t idx = 0, cIndex = 0, nc; michael@0: // Loop over the threads michael@0: for (i=0; i certdi(mDispInfo.SafeElementAt(certIndex, michael@0: nullptr)); michael@0: michael@0: // We will remove the element from the visual tree. michael@0: // Only if we have a certdi, then we can check for additional actions. michael@0: nsCOMPtr cert = nullptr; michael@0: if (certdi) { michael@0: if (certdi->mAddonInfo) { michael@0: cert = certdi->mAddonInfo->mCert; michael@0: } michael@0: nsCertAddonInfo *addonInfo = certdi->mAddonInfo ? certdi->mAddonInfo : nullptr; michael@0: if (certdi->mTypeOfEntry == nsCertTreeDispInfo::host_port_override) { michael@0: mOverrideService->ClearValidityOverride(certdi->mAsciiHost, certdi->mPort); michael@0: if (addonInfo) { michael@0: addonInfo->mUsageCount--; michael@0: if (addonInfo->mUsageCount == 0) { michael@0: // The certificate stored in the database is no longer michael@0: // referenced by any other object displayed. michael@0: // That means we no longer need to keep it around michael@0: // and really can remove it. michael@0: canRemoveEntry = true; michael@0: } michael@0: } michael@0: } michael@0: else { michael@0: if (addonInfo && addonInfo->mUsageCount > 1) { michael@0: // user is trying to delete a perm trusted cert, michael@0: // although there are still overrides stored, michael@0: // so, we keep the cert, but remove the trust michael@0: michael@0: mozilla::pkix::ScopedCERTCertificate nsscert; michael@0: michael@0: nsCOMPtr cert2 = do_QueryInterface(cert); michael@0: if (cert2) { michael@0: nsscert = cert2->GetCert(); michael@0: } michael@0: michael@0: if (nsscert) { michael@0: CERTCertTrust trust; michael@0: memset((void*)&trust, 0, sizeof(trust)); michael@0: michael@0: SECStatus srv = CERT_DecodeTrustString(&trust, ""); // no override michael@0: if (srv == SECSuccess) { michael@0: CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nsscert.get(), michael@0: &trust); michael@0: } michael@0: } michael@0: } michael@0: else { michael@0: canRemoveEntry = true; michael@0: } michael@0: } michael@0: } michael@0: michael@0: mDispInfo.RemoveElementAt(certIndex); michael@0: michael@0: if (canRemoveEntry) { michael@0: RemoveCacheEntry(cert); michael@0: certdb->DeleteCertificate(cert); michael@0: } michael@0: michael@0: delete [] mTreeArray; michael@0: mTreeArray = nullptr; michael@0: return UpdateUIContents(); michael@0: } michael@0: if (mTreeArray[i].open) michael@0: idx += mTreeArray[i].numChildren; michael@0: cIndex += mTreeArray[i].numChildren; michael@0: if (idx > index) michael@0: break; michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: ////////////////////////////////////////////////////////////////////////////// michael@0: // michael@0: // Begin nsITreeView methods michael@0: // michael@0: ///////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /* nsIX509Cert getCert(in unsigned long index); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::GetCert(uint32_t aIndex, nsIX509Cert **_cert) michael@0: { michael@0: NS_ENSURE_ARG(_cert); michael@0: *_cert = GetCertAtIndex(aIndex).take(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsCertTree::GetTreeItem(uint32_t aIndex, nsICertTreeItem **_treeitem) michael@0: { michael@0: NS_ENSURE_ARG(_treeitem); michael@0: michael@0: RefPtr certdi(GetDispInfoAtIndex(aIndex)); michael@0: if (!certdi) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: *_treeitem = certdi; michael@0: NS_IF_ADDREF(*_treeitem); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsCertTree::IsHostPortOverride(uint32_t aIndex, bool *_retval) michael@0: { michael@0: NS_ENSURE_ARG(_retval); michael@0: michael@0: RefPtr certdi(GetDispInfoAtIndex(aIndex)); michael@0: if (!certdi) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: *_retval = (certdi->mTypeOfEntry == nsCertTreeDispInfo::host_port_override); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute long rowCount; */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::GetRowCount(int32_t *aRowCount) michael@0: { michael@0: if (!mTreeArray) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: uint32_t count = 0; michael@0: for (int32_t i=0; iopen) { michael@0: *_retval = true; michael@0: } else { michael@0: *_retval = false; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean isContainerEmpty (in long index); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::IsContainerEmpty(int32_t index, bool *_retval) michael@0: { michael@0: *_retval = !mTreeArray; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean isSeparator (in long index); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::IsSeparator(int32_t index, bool *_retval) michael@0: { michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* long getParentIndex (in long rowIndex); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::GetParentIndex(int32_t rowIndex, int32_t *_retval) michael@0: { michael@0: if (!mTreeArray) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: int i, idx = 0; michael@0: for (i = 0; i < mNumOrgs && idx < rowIndex; i++, idx++) { michael@0: if (mTreeArray[i].open) { michael@0: if (rowIndex <= idx + mTreeArray[i].numChildren) { michael@0: *_retval = idx; michael@0: return NS_OK; michael@0: } michael@0: idx += mTreeArray[i].numChildren; michael@0: } michael@0: } michael@0: *_retval = -1; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean hasNextSibling (in long rowIndex, in long afterIndex); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::HasNextSibling(int32_t rowIndex, int32_t afterIndex, michael@0: bool *_retval) michael@0: { michael@0: if (!mTreeArray) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: int i, idx = 0; michael@0: for (i = 0; i < mNumOrgs && idx <= rowIndex; i++, idx++) { michael@0: if (mTreeArray[i].open) { michael@0: idx += mTreeArray[i].numChildren; michael@0: if (afterIndex <= idx) { michael@0: *_retval = afterIndex < idx; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* long getLevel (in long index); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::GetLevel(int32_t index, int32_t *_retval) michael@0: { michael@0: if (!mTreeArray) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: treeArrayEl *el = GetThreadDescAtIndex(index); michael@0: if (el) { michael@0: *_retval = 0; michael@0: } else { michael@0: *_retval = 1; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* Astring getImageSrc (in long row, in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::GetImageSrc(int32_t row, nsITreeColumn* col, michael@0: nsAString& _retval) michael@0: { michael@0: _retval.Truncate(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* long getProgressMode (in long row, in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::GetProgressMode(int32_t row, nsITreeColumn* col, int32_t* _retval) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* Astring getCellValue (in long row, in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::GetCellValue(int32_t row, nsITreeColumn* col, michael@0: nsAString& _retval) michael@0: { michael@0: _retval.Truncate(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* Astring getCellText (in long row, in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::GetCellText(int32_t row, nsITreeColumn* col, michael@0: nsAString& _retval) michael@0: { michael@0: if (!mTreeArray) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: nsresult rv; michael@0: _retval.Truncate(); michael@0: michael@0: const char16_t* colID; michael@0: col->GetIdConst(&colID); michael@0: michael@0: treeArrayEl *el = GetThreadDescAtIndex(row); michael@0: if (el) { michael@0: if (NS_LITERAL_STRING("certcol").Equals(colID)) michael@0: _retval.Assign(el->orgName); michael@0: else michael@0: _retval.Truncate(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: int32_t absoluteCertOffset; michael@0: RefPtr certdi(GetDispInfoAtIndex(row, &absoluteCertOffset)); michael@0: if (!certdi) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr cert = certdi->mCert; michael@0: if (!cert && certdi->mAddonInfo) { michael@0: cert = certdi->mAddonInfo->mCert; michael@0: } michael@0: michael@0: int32_t colIndex; michael@0: col->GetIndex(&colIndex); michael@0: uint32_t arrayIndex=absoluteCertOffset+colIndex*(mNumRows-mNumOrgs); michael@0: uint32_t arrayLength=0; michael@0: if (mCellText) { michael@0: mCellText->GetLength(&arrayLength); michael@0: } michael@0: if (arrayIndex < arrayLength) { michael@0: nsCOMPtr myString(do_QueryElementAt(mCellText, arrayIndex)); michael@0: if (myString) { michael@0: myString->GetData(_retval); michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: if (NS_LITERAL_STRING("certcol").Equals(colID)) { michael@0: if (!cert) { michael@0: mNSSComponent->GetPIPNSSBundleString("CertNotStored", _retval); michael@0: } michael@0: else { michael@0: rv = cert->GetCommonName(_retval); michael@0: if (NS_FAILED(rv) || _retval.IsEmpty()) { michael@0: // kaie: I didn't invent the idea to cut off anything before michael@0: // the first colon. :-) michael@0: nsAutoString nick; michael@0: rv = cert->GetNickname(nick); michael@0: michael@0: nsAString::const_iterator start, end, end2; michael@0: nick.BeginReading(start); michael@0: nick.EndReading(end); michael@0: end2 = end; michael@0: michael@0: if (FindInReadable(NS_LITERAL_STRING(":"), start, end)) { michael@0: // found. end points to the first char after the colon, michael@0: // that's what we want. michael@0: _retval = Substring(end, end2); michael@0: } michael@0: else { michael@0: _retval = nick; michael@0: } michael@0: } michael@0: } michael@0: } else if (NS_LITERAL_STRING("tokencol").Equals(colID) && cert) { michael@0: rv = cert->GetTokenName(_retval); michael@0: } else if (NS_LITERAL_STRING("emailcol").Equals(colID) && cert) { michael@0: rv = cert->GetEmailAddress(_retval); michael@0: } else if (NS_LITERAL_STRING("purposecol").Equals(colID) && mNSSComponent && cert) { michael@0: uint32_t verified; michael@0: michael@0: nsAutoString theUsages; michael@0: rv = cert->GetUsagesString(false, &verified, theUsages); // allow OCSP michael@0: if (NS_FAILED(rv)) { michael@0: verified = nsIX509Cert::NOT_VERIFIED_UNKNOWN; michael@0: } michael@0: michael@0: switch (verified) { michael@0: case nsIX509Cert::VERIFIED_OK: michael@0: _retval = theUsages; michael@0: break; michael@0: michael@0: case nsIX509Cert::CERT_REVOKED: michael@0: rv = mNSSComponent->GetPIPNSSBundleString("VerifyRevoked", _retval); michael@0: break; michael@0: case nsIX509Cert::CERT_EXPIRED: michael@0: rv = mNSSComponent->GetPIPNSSBundleString("VerifyExpired", _retval); michael@0: break; michael@0: case nsIX509Cert::CERT_NOT_TRUSTED: michael@0: rv = mNSSComponent->GetPIPNSSBundleString("VerifyNotTrusted", _retval); michael@0: break; michael@0: case nsIX509Cert::ISSUER_NOT_TRUSTED: michael@0: rv = mNSSComponent->GetPIPNSSBundleString("VerifyIssuerNotTrusted", _retval); michael@0: break; michael@0: case nsIX509Cert::ISSUER_UNKNOWN: michael@0: rv = mNSSComponent->GetPIPNSSBundleString("VerifyIssuerUnknown", _retval); michael@0: break; michael@0: case nsIX509Cert::INVALID_CA: michael@0: rv = mNSSComponent->GetPIPNSSBundleString("VerifyInvalidCA", _retval); michael@0: break; michael@0: case nsIX509Cert::SIGNATURE_ALGORITHM_DISABLED: michael@0: rv = mNSSComponent->GetPIPNSSBundleString("VerifyDisabledAlgorithm", _retval); michael@0: break; michael@0: case nsIX509Cert::NOT_VERIFIED_UNKNOWN: michael@0: case nsIX509Cert::USAGE_NOT_ALLOWED: michael@0: default: michael@0: rv = mNSSComponent->GetPIPNSSBundleString("VerifyUnknown", _retval); michael@0: break; michael@0: } michael@0: } else if (NS_LITERAL_STRING("issuedcol").Equals(colID) && cert) { michael@0: nsCOMPtr validity; michael@0: michael@0: rv = cert->GetValidity(getter_AddRefs(validity)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: validity->GetNotBeforeLocalDay(_retval); michael@0: } michael@0: } else if (NS_LITERAL_STRING("expiredcol").Equals(colID) && cert) { michael@0: nsCOMPtr validity; michael@0: michael@0: rv = cert->GetValidity(getter_AddRefs(validity)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: validity->GetNotAfterLocalDay(_retval); michael@0: } michael@0: } else if (NS_LITERAL_STRING("serialnumcol").Equals(colID) && cert) { michael@0: rv = cert->GetSerialNumber(_retval); michael@0: michael@0: michael@0: } else if (NS_LITERAL_STRING("overridetypecol").Equals(colID)) { michael@0: // default to classic permanent-trust michael@0: nsCertOverride::OverrideBits ob = nsCertOverride::ob_Untrusted; michael@0: if (certdi->mTypeOfEntry == nsCertTreeDispInfo::host_port_override) { michael@0: ob = certdi->mOverrideBits; michael@0: } michael@0: nsAutoCString temp; michael@0: nsCertOverride::convertBitsToString(ob, temp); michael@0: _retval = NS_ConvertUTF8toUTF16(temp); michael@0: } else if (NS_LITERAL_STRING("sitecol").Equals(colID)) { michael@0: if (certdi->mTypeOfEntry == nsCertTreeDispInfo::host_port_override) { michael@0: nsAutoCString hostPort; michael@0: nsCertOverrideService::GetHostWithPort(certdi->mAsciiHost, certdi->mPort, hostPort); michael@0: _retval = NS_ConvertUTF8toUTF16(hostPort); michael@0: } michael@0: else { michael@0: _retval = NS_LITERAL_STRING("*"); michael@0: } michael@0: } else if (NS_LITERAL_STRING("lifetimecol").Equals(colID)) { michael@0: const char *stringID = michael@0: (certdi->mIsTemporary) ? "CertExceptionTemporary" : "CertExceptionPermanent"; michael@0: rv = mNSSComponent->GetPIPNSSBundleString(stringID, _retval); michael@0: } else if (NS_LITERAL_STRING("typecol").Equals(colID) && cert) { michael@0: nsCOMPtr pipCert = do_QueryInterface(cert); michael@0: uint32_t type = nsIX509Cert::UNKNOWN_CERT; michael@0: michael@0: if (pipCert) { michael@0: rv = pipCert->GetCertType(&type); michael@0: } michael@0: michael@0: switch (type) { michael@0: case nsIX509Cert::USER_CERT: michael@0: rv = mNSSComponent->GetPIPNSSBundleString("CertUser", _retval); michael@0: break; michael@0: case nsIX509Cert::CA_CERT: michael@0: rv = mNSSComponent->GetPIPNSSBundleString("CertCA", _retval); michael@0: break; michael@0: case nsIX509Cert::SERVER_CERT: michael@0: rv = mNSSComponent->GetPIPNSSBundleString("CertSSL", _retval); michael@0: break; michael@0: case nsIX509Cert::EMAIL_CERT: michael@0: rv = mNSSComponent->GetPIPNSSBundleString("CertEmail", _retval); michael@0: break; michael@0: default: michael@0: rv = mNSSComponent->GetPIPNSSBundleString("CertUnknown", _retval); michael@0: break; michael@0: } michael@0: michael@0: } else { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: if (mCellText) { michael@0: nsCOMPtr text(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: text->SetData(_retval); michael@0: mCellText->ReplaceElementAt(text, arrayIndex, false); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: /* void setTree (in nsITreeBoxObject tree); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::SetTree(nsITreeBoxObject *tree) michael@0: { michael@0: mTree = tree; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void toggleOpenState (in long index); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::ToggleOpenState(int32_t index) michael@0: { michael@0: if (!mTreeArray) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: treeArrayEl *el = GetThreadDescAtIndex(index); michael@0: if (el) { michael@0: el->open = !el->open; michael@0: int32_t newChildren = (el->open) ? el->numChildren : -el->numChildren; michael@0: if (mTree) mTree->RowCountChanged(index + 1, newChildren); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void cycleHeader (in nsITreeColumn); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::CycleHeader(nsITreeColumn* col) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void selectionChanged (); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::SelectionChanged() michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: /* void cycleCell (in long row, in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::CycleCell(int32_t row, nsITreeColumn* col) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean isEditable (in long row, in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::IsEditable(int32_t row, nsITreeColumn* col, bool *_retval) michael@0: { michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean isSelectable (in long row, in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::IsSelectable(int32_t row, nsITreeColumn* col, bool *_retval) michael@0: { michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void setCellValue (in long row, in nsITreeColumn col, in AString value); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::SetCellValue(int32_t row, nsITreeColumn* col, michael@0: const nsAString& value) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void setCellText (in long row, in nsITreeColumn col, in AString value); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::SetCellText(int32_t row, nsITreeColumn* col, michael@0: const nsAString& value) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void performAction (in wstring action); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::PerformAction(const char16_t *action) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void performActionOnRow (in wstring action, in long row); */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::PerformActionOnRow(const char16_t *action, int32_t row) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void performActionOnCell (in wstring action, in long row, michael@0: * in wstring colID); michael@0: */ michael@0: NS_IMETHODIMP michael@0: nsCertTree::PerformActionOnCell(const char16_t *action, int32_t row, michael@0: nsITreeColumn* col) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: #ifdef DEBUG_CERT_TREE michael@0: void michael@0: nsCertTree::dumpMap() michael@0: { michael@0: for (int i=0; iorgName); michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("thread desc[%d]: %s", i, NS_LossyConvertUTF16toASCII(td).get())); michael@0: } michael@0: nsCOMPtr ct = GetCertAtIndex(i); michael@0: if (ct) { michael@0: char16_t *goo; michael@0: ct->GetCommonName(&goo); michael@0: nsAutoString doo(goo); michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("cert [%d]: %s", i, NS_LossyConvertUTF16toASCII(doo).get())); michael@0: } michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: // michael@0: // CanDrop michael@0: // michael@0: NS_IMETHODIMP nsCertTree::CanDrop(int32_t index, int32_t orientation, michael@0: nsIDOMDataTransfer* aDataTransfer, bool *_retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_retval); michael@0: *_retval = false; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: // michael@0: // Drop michael@0: // michael@0: NS_IMETHODIMP nsCertTree::Drop(int32_t row, int32_t orient, nsIDOMDataTransfer* aDataTransfer) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: // michael@0: // IsSorted michael@0: // michael@0: // ... michael@0: // michael@0: NS_IMETHODIMP nsCertTree::IsSorted(bool *_retval) michael@0: { michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: #define RETURN_NOTHING michael@0: michael@0: void michael@0: nsCertTree::CmpInitCriterion(nsIX509Cert *cert, CompareCacheHashEntry *entry, michael@0: sortCriterion crit, int32_t level) michael@0: { michael@0: NS_ENSURE_TRUE(cert && entry, RETURN_NOTHING); michael@0: michael@0: entry->mCritInit[level] = true; michael@0: nsXPIDLString &str = entry->mCrit[level]; michael@0: michael@0: switch (crit) { michael@0: case sort_IssuerOrg: michael@0: cert->GetIssuerOrganization(str); michael@0: if (str.IsEmpty()) michael@0: cert->GetCommonName(str); michael@0: break; michael@0: case sort_Org: michael@0: cert->GetOrganization(str); michael@0: break; michael@0: case sort_Token: michael@0: cert->GetTokenName(str); michael@0: break; michael@0: case sort_CommonName: michael@0: cert->GetCommonName(str); michael@0: break; michael@0: case sort_IssuedDateDescending: michael@0: { michael@0: nsresult rv; michael@0: nsCOMPtr validity; michael@0: PRTime notBefore; michael@0: michael@0: rv = cert->GetValidity(getter_AddRefs(validity)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: rv = validity->GetNotBefore(¬Before); michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(rv)) { michael@0: PRExplodedTime explodedTime; michael@0: PR_ExplodeTime(notBefore, PR_GMTParameters, &explodedTime); michael@0: char datebuf[20]; // 4 + 2 + 2 + 2 + 2 + 2 + 1 = 15 michael@0: if (0 != PR_FormatTime(datebuf, sizeof(datebuf), "%Y%m%d%H%M%S", &explodedTime)) { michael@0: str = NS_ConvertASCIItoUTF16(nsDependentCString(datebuf)); michael@0: } michael@0: } michael@0: } michael@0: break; michael@0: case sort_Email: michael@0: cert->GetEmailAddress(str); michael@0: break; michael@0: case sort_None: michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: michael@0: int32_t michael@0: nsCertTree::CmpByCrit(nsIX509Cert *a, CompareCacheHashEntry *ace, michael@0: nsIX509Cert *b, CompareCacheHashEntry *bce, michael@0: sortCriterion crit, int32_t level) michael@0: { michael@0: NS_ENSURE_TRUE(a && ace && b && bce, 0); michael@0: michael@0: if (!ace->mCritInit[level]) { michael@0: CmpInitCriterion(a, ace, crit, level); michael@0: } michael@0: michael@0: if (!bce->mCritInit[level]) { michael@0: CmpInitCriterion(b, bce, crit, level); michael@0: } michael@0: michael@0: nsXPIDLString &str_a = ace->mCrit[level]; michael@0: nsXPIDLString &str_b = bce->mCrit[level]; michael@0: michael@0: int32_t result; michael@0: if (str_a && str_b) michael@0: result = Compare(str_a, str_b, nsCaseInsensitiveStringComparator()); michael@0: else michael@0: result = !str_a ? (!str_b ? 0 : -1) : 1; michael@0: michael@0: if (sort_IssuedDateDescending == crit) michael@0: result *= -1; // reverse compare order michael@0: michael@0: return result; michael@0: } michael@0: michael@0: int32_t michael@0: nsCertTree::CmpBy(void *cache, nsIX509Cert *a, nsIX509Cert *b, michael@0: sortCriterion c0, sortCriterion c1, sortCriterion c2) michael@0: { michael@0: // This will be called when comparing items for display sorting. michael@0: // Some items might have no cert associated, so either a or b is null. michael@0: // We want all those orphans show at the top of the list, michael@0: // so we treat a null cert as "smaller" by returning -1. michael@0: // We don't try to sort within the group of no-cert entries, michael@0: // so we treat them as equal wrt sort order. michael@0: michael@0: if (!a && !b) michael@0: return 0; michael@0: michael@0: if (!a) michael@0: return -1; michael@0: michael@0: if (!b) michael@0: return 1; michael@0: michael@0: NS_ENSURE_TRUE(cache && a && b, 0); michael@0: michael@0: CompareCacheHashEntry *ace = getCacheEntry(cache, a); michael@0: CompareCacheHashEntry *bce = getCacheEntry(cache, b); michael@0: michael@0: int32_t cmp; michael@0: cmp = CmpByCrit(a, ace, b, bce, c0, 0); michael@0: if (cmp != 0) michael@0: return cmp; michael@0: michael@0: if (c1 != sort_None) { michael@0: cmp = CmpByCrit(a, ace, b, bce, c1, 1); michael@0: if (cmp != 0) michael@0: return cmp; michael@0: michael@0: if (c2 != sort_None) { michael@0: return CmpByCrit(a, ace, b, bce, c2, 2); michael@0: } michael@0: } michael@0: michael@0: return cmp; michael@0: } michael@0: michael@0: int32_t michael@0: nsCertTree::CmpCACert(void *cache, nsIX509Cert *a, nsIX509Cert *b) michael@0: { michael@0: // XXX we assume issuer org is always criterion 1 michael@0: return CmpBy(cache, a, b, sort_IssuerOrg, sort_Org, sort_Token); michael@0: } michael@0: michael@0: int32_t michael@0: nsCertTree::CmpWebSiteCert(void *cache, nsIX509Cert *a, nsIX509Cert *b) michael@0: { michael@0: // XXX we assume issuer org is always criterion 1 michael@0: return CmpBy(cache, a, b, sort_IssuerOrg, sort_CommonName, sort_None); michael@0: } michael@0: michael@0: int32_t michael@0: nsCertTree::CmpUserCert(void *cache, nsIX509Cert *a, nsIX509Cert *b) michael@0: { michael@0: // XXX we assume issuer org is always criterion 1 michael@0: return CmpBy(cache, a, b, sort_IssuerOrg, sort_Token, sort_IssuedDateDescending); michael@0: } michael@0: michael@0: int32_t michael@0: nsCertTree::CmpEmailCert(void *cache, nsIX509Cert *a, nsIX509Cert *b) michael@0: { michael@0: // XXX we assume issuer org is always criterion 1 michael@0: return CmpBy(cache, a, b, sort_IssuerOrg, sort_Email, sort_CommonName); michael@0: } michael@0: