Merge branch 'master' into f23
This commit is contained in:
commit
6285b766cc
@ -26,4 +26,6 @@ pref("media.gmp-gmpopenh264.enabled",false);
|
|||||||
pref("plugins.notifyMissingFlash", false);
|
pref("plugins.notifyMissingFlash", false);
|
||||||
/* See https://bugzilla.redhat.com/show_bug.cgi?id=1226489 */
|
/* See https://bugzilla.redhat.com/show_bug.cgi?id=1226489 */
|
||||||
pref("browser.display.use_system_colors", false);
|
pref("browser.display.use_system_colors", false);
|
||||||
pref("layers.use-image-offscreen-surfaces", false);
|
pref("layers.use-image-offscreen-surfaces", false);
|
||||||
|
/* Allow sending credetials to all https:// sites */
|
||||||
|
pref("network.negotiate-auth.trusted-uris", "https://")
|
||||||
|
@ -85,7 +85,7 @@
|
|||||||
Summary: Mozilla Firefox Web browser
|
Summary: Mozilla Firefox Web browser
|
||||||
Name: firefox
|
Name: firefox
|
||||||
Version: 46.0.1
|
Version: 46.0.1
|
||||||
Release: 8%{?pre_tag}%{?dist}
|
Release: 9%{?pre_tag}%{?dist}
|
||||||
URL: https://www.mozilla.org/firefox/
|
URL: https://www.mozilla.org/firefox/
|
||||||
License: MPLv1.1 or GPLv2+ or LGPLv2+
|
License: MPLv1.1 or GPLv2+ or LGPLv2+
|
||||||
Group: Applications/Internet
|
Group: Applications/Internet
|
||||||
@ -101,7 +101,7 @@ Source23: firefox.1
|
|||||||
Source24: mozilla-api-key
|
Source24: mozilla-api-key
|
||||||
Source25: firefox-symbolic.svg
|
Source25: firefox-symbolic.svg
|
||||||
|
|
||||||
#Build patches
|
# Build patches
|
||||||
Patch0: firefox-install-dir.patch
|
Patch0: firefox-install-dir.patch
|
||||||
Patch3: mozilla-build-arm.patch
|
Patch3: mozilla-build-arm.patch
|
||||||
# https://bugzilla.redhat.com/show_bug.cgi?id=814879#c3
|
# https://bugzilla.redhat.com/show_bug.cgi?id=814879#c3
|
||||||
@ -133,6 +133,7 @@ Patch403: mozilla-1216658.patch
|
|||||||
Patch404: mozilla-1270046.patch
|
Patch404: mozilla-1270046.patch
|
||||||
# Remove when mozbz#1269319 lands
|
# Remove when mozbz#1269319 lands
|
||||||
Patch405: mozilla-1245783.patch
|
Patch405: mozilla-1245783.patch
|
||||||
|
Patch406: mozilla-890908-async-negotiate.patch
|
||||||
|
|
||||||
# Debian patches
|
# Debian patches
|
||||||
Patch500: mozilla-440908.patch
|
Patch500: mozilla-440908.patch
|
||||||
@ -280,6 +281,7 @@ cd %{tarballdir}
|
|||||||
%patch403 -p1 -b .1216658
|
%patch403 -p1 -b .1216658
|
||||||
%patch404 -p1 -b .1270046
|
%patch404 -p1 -b .1270046
|
||||||
%patch405 -p1 -b .1245783
|
%patch405 -p1 -b .1245783
|
||||||
|
%patch406 -p1 -b .890908-async-negotiate
|
||||||
|
|
||||||
# Debian extension patch
|
# Debian extension patch
|
||||||
%patch500 -p1 -b .440908
|
%patch500 -p1 -b .440908
|
||||||
@ -791,6 +793,9 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
|
|||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Thu May 26 2016 Jan Horak <jhorak@redhat.com> - 46.0.1-9
|
||||||
|
- Negotiate authentication is made off the main thread (mozbz#890908)
|
||||||
|
|
||||||
* Mon May 23 2016 Martin Stransky <stransky@redhat.com> - 46.0.1-8
|
* Mon May 23 2016 Martin Stransky <stransky@redhat.com> - 46.0.1-8
|
||||||
- Rebuilt for new bookmarks (rhbz#1338010)
|
- Rebuilt for new bookmarks (rhbz#1338010)
|
||||||
- Fixed build issue in Gtk3.20 patch
|
- Fixed build issue in Gtk3.20 patch
|
||||||
|
737
mozilla-890908-async-negotiate.patch
Normal file
737
mozilla-890908-async-negotiate.patch
Normal file
@ -0,0 +1,737 @@
|
|||||||
|
diff -up firefox-46.0.1/extensions/auth/nsHttpNegotiateAuth.cpp.890908-async-negotiate firefox-46.0.1/extensions/auth/nsHttpNegotiateAuth.cpp
|
||||||
|
--- firefox-46.0.1/extensions/auth/nsHttpNegotiateAuth.cpp.890908-async-negotiate 2016-05-03 07:31:11.000000000 +0200
|
||||||
|
+++ firefox-46.0.1/extensions/auth/nsHttpNegotiateAuth.cpp 2016-05-26 15:10:23.850901737 +0200
|
||||||
|
@@ -38,6 +38,10 @@
|
||||||
|
#include "prnetdb.h"
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
#include "mozilla/Snprintf.h"
|
||||||
|
+#include "nsThreadUtils.h"
|
||||||
|
+#include "nsIHttpAuthenticatorCallback.h"
|
||||||
|
+#include "mozilla/Mutex.h"
|
||||||
|
+#include "nsICancelable.h"
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@@ -49,6 +53,7 @@ static const char kNegotiateAuthAllowNon
|
||||||
|
static const char kNegotiateAuthSSPI[] = "network.auth.use-sspi";
|
||||||
|
|
||||||
|
#define kNegotiateLen (sizeof(kNegotiate)-1)
|
||||||
|
+#define DEFAULT_THREAD_TIMEOUT_MS 30000
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@@ -172,7 +177,237 @@ nsHttpNegotiateAuth::ChallengeReceived(n
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(nsHttpNegotiateAuth, nsIHttpAuthenticator)
|
||||||
|
-
|
||||||
|
+
|
||||||
|
+namespace {
|
||||||
|
+
|
||||||
|
+//
|
||||||
|
+// GetNextTokenCompleteEvent
|
||||||
|
+//
|
||||||
|
+// This event is fired on main thread when async call of
|
||||||
|
+// nsHttpNegotiateAuth::GenerateCredentials is finished. During the Run()
|
||||||
|
+// method the nsIHttpAuthenticatorCallback::OnCredsAvailable is called with
|
||||||
|
+// obtained credentials, flags and NS_OK when successful, otherwise
|
||||||
|
+// NS_ERROR_FAILURE is returned as a result of failed operation.
|
||||||
|
+//
|
||||||
|
+class GetNextTokenCompleteEvent final : public nsIRunnable,
|
||||||
|
+ public nsICancelable
|
||||||
|
+{
|
||||||
|
+ virtual ~GetNextTokenCompleteEvent()
|
||||||
|
+ {
|
||||||
|
+ if (mCreds) {
|
||||||
|
+ free(mCreds);
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+public:
|
||||||
|
+ NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
+
|
||||||
|
+ explicit GetNextTokenCompleteEvent(nsIHttpAuthenticatorCallback* aCallback)
|
||||||
|
+ : mCallback(aCallback)
|
||||||
|
+ , mCreds(nullptr)
|
||||||
|
+ , mCancelled(false)
|
||||||
|
+ {
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ NS_IMETHODIMP DispatchSuccess(char *aCreds,
|
||||||
|
+ uint32_t aFlags,
|
||||||
|
+ nsISupports *aSessionState,
|
||||||
|
+ nsISupports *aContinuationState)
|
||||||
|
+ {
|
||||||
|
+ // Called from worker thread
|
||||||
|
+ MOZ_ASSERT(!NS_IsMainThread());
|
||||||
|
+
|
||||||
|
+ mCreds = aCreds;
|
||||||
|
+ mFlags = aFlags;
|
||||||
|
+ mResult = NS_OK;
|
||||||
|
+ mSessionState = aSessionState;
|
||||||
|
+ mContinuationState = aContinuationState;
|
||||||
|
+ return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ NS_IMETHODIMP DispatchError()
|
||||||
|
+ {
|
||||||
|
+ // Called from worker thread
|
||||||
|
+ MOZ_ASSERT(!NS_IsMainThread());
|
||||||
|
+
|
||||||
|
+ mResult = NS_ERROR_FAILURE;
|
||||||
|
+ return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ NS_IMETHODIMP Run() override
|
||||||
|
+ {
|
||||||
|
+ // Runs on main thread
|
||||||
|
+ MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
+
|
||||||
|
+ if (!mCancelled) {
|
||||||
|
+ nsCOMPtr<nsIHttpAuthenticatorCallback> callback;
|
||||||
|
+ callback.swap(mCallback);
|
||||||
|
+ callback->OnCredsGenerated(mCreds, mFlags, mResult, mSessionState, mContinuationState);
|
||||||
|
+ }
|
||||||
|
+ return NS_OK;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ NS_IMETHODIMP Cancel(nsresult aReason) override
|
||||||
|
+ {
|
||||||
|
+ // Supposed to be called from main thread
|
||||||
|
+ MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
+
|
||||||
|
+ mCancelled = true;
|
||||||
|
+ return NS_OK;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+private:
|
||||||
|
+ nsCOMPtr<nsIHttpAuthenticatorCallback> mCallback;
|
||||||
|
+ char *mCreds; // This class owns it, freed in destructor
|
||||||
|
+ uint32_t mFlags;
|
||||||
|
+ nsresult mResult;
|
||||||
|
+ bool mCancelled;
|
||||||
|
+ nsCOMPtr<nsISupports> mSessionState;
|
||||||
|
+ nsCOMPtr<nsISupports> mContinuationState;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+NS_IMPL_ISUPPORTS(GetNextTokenCompleteEvent, nsIRunnable, nsICancelable)
|
||||||
|
+
|
||||||
|
+//
|
||||||
|
+// GetNextTokenRunnable
|
||||||
|
+//
|
||||||
|
+// This runnable is created by GenerateCredentialsAsync and it runs
|
||||||
|
+// in nsHttpNegotiateAuth::mNegotiateThread and calling GenerateCredentials.
|
||||||
|
+//
|
||||||
|
+class GetNextTokenRunnable final : public nsRunnable
|
||||||
|
+{
|
||||||
|
+ virtual ~GetNextTokenRunnable() {}
|
||||||
|
+ public:
|
||||||
|
+ GetNextTokenRunnable(nsIHttpAuthenticableChannel *authChannel,
|
||||||
|
+ const char *challenge,
|
||||||
|
+ bool isProxyAuth,
|
||||||
|
+ const char16_t *domain,
|
||||||
|
+ const char16_t *username,
|
||||||
|
+ const char16_t *password,
|
||||||
|
+ nsISupports *sessionState,
|
||||||
|
+ nsISupports *continuationState,
|
||||||
|
+ GetNextTokenCompleteEvent *aCompleteEvent
|
||||||
|
+ )
|
||||||
|
+ : mAuthChannel(authChannel)
|
||||||
|
+ , mChallenge(challenge)
|
||||||
|
+ , mIsProxyAuth(isProxyAuth)
|
||||||
|
+ , mDomain(domain)
|
||||||
|
+ , mUsername(username)
|
||||||
|
+ , mPassword(password)
|
||||||
|
+ , mSessionState(sessionState)
|
||||||
|
+ , mContinuationState(continuationState)
|
||||||
|
+ , mCompleteEvent(aCompleteEvent)
|
||||||
|
+ {
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ NS_IMETHODIMP Run() override
|
||||||
|
+ {
|
||||||
|
+ // Runs on worker thread
|
||||||
|
+ MOZ_ASSERT(!NS_IsMainThread());
|
||||||
|
+
|
||||||
|
+ char *creds;
|
||||||
|
+ uint32_t flags;
|
||||||
|
+ nsresult rv = ObtainCredentialsAndFlags(&creds, &flags);
|
||||||
|
+ if (NS_FAILED(rv)) {
|
||||||
|
+ return mCompleteEvent->DispatchError();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return mCompleteEvent->DispatchSuccess(creds, flags, mSessionState, mContinuationState);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ NS_IMETHODIMP ObtainCredentialsAndFlags(char **aCreds, uint32_t *aFlags)
|
||||||
|
+ {
|
||||||
|
+ // Use negotiate service to call GenerateCredentials outside of main thread
|
||||||
|
+ nsAutoCString contractId;
|
||||||
|
+ contractId.Assign(NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX);
|
||||||
|
+ contractId.Append("negotiate");
|
||||||
|
+ nsresult rv;
|
||||||
|
+ nsCOMPtr<nsIHttpAuthenticator> authenticator = do_GetService(contractId.get(), &rv);
|
||||||
|
+ NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
+ nsISupports *sessionState = mSessionState;
|
||||||
|
+ nsISupports *continuationState = mContinuationState;
|
||||||
|
+ // The continuationState is for the sake of completeness propagated
|
||||||
|
+ // to the caller (despite it is not changed in any GenerateCredentials
|
||||||
|
+ // implementation).
|
||||||
|
+ //
|
||||||
|
+ // The only implementation that use sessionState is the
|
||||||
|
+ // nsHttpDigestAuth::GenerateCredentials. Since there's no reason
|
||||||
|
+ // to implement nsHttpDigestAuth::GenerateCredentialsAsync
|
||||||
|
+ // because digest auth does not block the main thread, we won't
|
||||||
|
+ // propagate changes to sessionState to the caller because of
|
||||||
|
+ // the change is too complicated on the caller side.
|
||||||
|
+ rv = authenticator->GenerateCredentials(mAuthChannel,
|
||||||
|
+ mChallenge.get(),
|
||||||
|
+ mIsProxyAuth,
|
||||||
|
+ mDomain.get(),
|
||||||
|
+ mUsername.get(),
|
||||||
|
+ mPassword.get(),
|
||||||
|
+ &sessionState,
|
||||||
|
+ &continuationState,
|
||||||
|
+ aFlags,
|
||||||
|
+ aCreds);
|
||||||
|
+ mSessionState = sessionState;
|
||||||
|
+ mContinuationState = continuationState;
|
||||||
|
+ return rv;
|
||||||
|
+ }
|
||||||
|
+ private:
|
||||||
|
+ nsCOMPtr<nsIHttpAuthenticableChannel> mAuthChannel;
|
||||||
|
+ nsCString mChallenge;
|
||||||
|
+ bool mIsProxyAuth;
|
||||||
|
+ nsString mDomain;
|
||||||
|
+ nsString mUsername;
|
||||||
|
+ nsString mPassword;
|
||||||
|
+ nsCOMPtr<nsISupports> mSessionState;
|
||||||
|
+ nsCOMPtr<nsISupports> mContinuationState;
|
||||||
|
+ RefPtr<GetNextTokenCompleteEvent> mCompleteEvent;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+} // anonymous namespace
|
||||||
|
+
|
||||||
|
+NS_IMETHODIMP
|
||||||
|
+nsHttpNegotiateAuth::GenerateCredentialsAsync(nsIHttpAuthenticableChannel *authChannel,
|
||||||
|
+ nsIHttpAuthenticatorCallback* aCallback,
|
||||||
|
+ const char *challenge,
|
||||||
|
+ bool isProxyAuth,
|
||||||
|
+ const char16_t *domain,
|
||||||
|
+ const char16_t *username,
|
||||||
|
+ const char16_t *password,
|
||||||
|
+ nsISupports *sessionState,
|
||||||
|
+ nsISupports *continuationState,
|
||||||
|
+ nsICancelable **aCancelable)
|
||||||
|
+{
|
||||||
|
+ NS_ENSURE_ARG(aCallback);
|
||||||
|
+ NS_ENSURE_ARG_POINTER(aCancelable);
|
||||||
|
+
|
||||||
|
+ RefPtr<GetNextTokenCompleteEvent> cancelEvent =
|
||||||
|
+ new GetNextTokenCompleteEvent(aCallback);
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ nsCOMPtr<nsIRunnable> getNextTokenRunnable =
|
||||||
|
+ new GetNextTokenRunnable(authChannel,
|
||||||
|
+ challenge,
|
||||||
|
+ isProxyAuth,
|
||||||
|
+ domain,
|
||||||
|
+ username,
|
||||||
|
+ password,
|
||||||
|
+ sessionState,
|
||||||
|
+ continuationState,
|
||||||
|
+ cancelEvent);
|
||||||
|
+ cancelEvent.forget(aCancelable);
|
||||||
|
+
|
||||||
|
+ nsresult rv;
|
||||||
|
+ if (!mNegotiateThread) {
|
||||||
|
+ mNegotiateThread =
|
||||||
|
+ new mozilla::LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
|
||||||
|
+ NS_LITERAL_CSTRING("NegotiateAuth"));
|
||||||
|
+ NS_ENSURE_TRUE(mNegotiateThread, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
+ }
|
||||||
|
+ rv = mNegotiateThread->Dispatch(getNextTokenRunnable, NS_DISPATCH_NORMAL);
|
||||||
|
+ NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
+
|
||||||
|
+ return NS_OK;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
//
|
||||||
|
// GenerateCredentials
|
||||||
|
//
|
||||||
|
diff -up firefox-46.0.1/extensions/auth/nsHttpNegotiateAuth.h.890908-async-negotiate firefox-46.0.1/extensions/auth/nsHttpNegotiateAuth.h
|
||||||
|
--- firefox-46.0.1/extensions/auth/nsHttpNegotiateAuth.h.890908-async-negotiate 2016-05-03 07:31:11.000000000 +0200
|
||||||
|
+++ firefox-46.0.1/extensions/auth/nsHttpNegotiateAuth.h 2016-05-26 15:04:33.971068476 +0200
|
||||||
|
@@ -10,6 +10,7 @@
|
||||||
|
#include "nsIURI.h"
|
||||||
|
#include "nsSubstring.h"
|
||||||
|
#include "mozilla/Attributes.h"
|
||||||
|
+#include "mozilla/LazyIdleThread.h"
|
||||||
|
|
||||||
|
// The nsHttpNegotiateAuth class provides responses for the GSS-API Negotiate method
|
||||||
|
// as specified by Microsoft in draft-brezak-spnego-http-04.txt
|
||||||
|
@@ -17,7 +18,7 @@
|
||||||
|
class nsHttpNegotiateAuth final : public nsIHttpAuthenticator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
- NS_DECL_ISUPPORTS
|
||||||
|
+ NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
NS_DECL_NSIHTTPAUTHENTICATOR
|
||||||
|
|
||||||
|
private:
|
||||||
|
@@ -37,5 +38,7 @@ private:
|
||||||
|
int32_t port,
|
||||||
|
const char *baseStart,
|
||||||
|
const char *baseEnd);
|
||||||
|
+ // Thread for GenerateCredentialsAsync
|
||||||
|
+ RefPtr<mozilla::LazyIdleThread> mNegotiateThread;
|
||||||
|
};
|
||||||
|
#endif /* nsHttpNegotiateAuth_h__ */
|
||||||
|
diff -up firefox-46.0.1/netwerk/base/moz.build.890908-async-negotiate firefox-46.0.1/netwerk/base/moz.build
|
||||||
|
--- firefox-46.0.1/netwerk/base/moz.build.890908-async-negotiate 2016-05-03 07:31:07.000000000 +0200
|
||||||
|
+++ firefox-46.0.1/netwerk/base/moz.build 2016-05-26 15:04:33.971068476 +0200
|
||||||
|
@@ -46,6 +46,7 @@ XPIDL_SOURCES += [
|
||||||
|
'nsIFileStreams.idl',
|
||||||
|
'nsIFileURL.idl',
|
||||||
|
'nsIForcePendingChannel.idl',
|
||||||
|
+ 'nsIHttpAuthenticatorCallback.idl',
|
||||||
|
'nsIHttpPushListener.idl',
|
||||||
|
'nsIIncrementalDownload.idl',
|
||||||
|
'nsIIncrementalStreamLoader.idl',
|
||||||
|
diff -up firefox-46.0.1/netwerk/base/nsIHttpAuthenticatorCallback.idl.890908-async-negotiate firefox-46.0.1/netwerk/base/nsIHttpAuthenticatorCallback.idl
|
||||||
|
--- firefox-46.0.1/netwerk/base/nsIHttpAuthenticatorCallback.idl.890908-async-negotiate 2016-05-26 15:04:33.971068476 +0200
|
||||||
|
+++ firefox-46.0.1/netwerk/base/nsIHttpAuthenticatorCallback.idl 2016-05-26 15:04:33.971068476 +0200
|
||||||
|
@@ -0,0 +1,31 @@
|
||||||
|
+/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
+
|
||||||
|
+#include "nsISupports.idl"
|
||||||
|
+
|
||||||
|
+[scriptable, uuid(d989cb03-e446-4086-b9e6-46842cb97bd5)]
|
||||||
|
+interface nsIHttpAuthenticatorCallback : nsISupports
|
||||||
|
+{
|
||||||
|
+ /**
|
||||||
|
+ * Authentication data for a header is available.
|
||||||
|
+ *
|
||||||
|
+ * @param aCreds
|
||||||
|
+ * Credentials which were obtained asynchonously.
|
||||||
|
+ * @param aFlags
|
||||||
|
+ * Flags set by asynchronous call.
|
||||||
|
+ * @param aResult
|
||||||
|
+ * Result status of credentials generation
|
||||||
|
+ * @param aSessionState
|
||||||
|
+ * Modified session state to be passed to caller
|
||||||
|
+ * @param aContinuationState
|
||||||
|
+ * Modified continuation state to be passed to caller
|
||||||
|
+ */
|
||||||
|
+ void onCredsGenerated(in string aCreds,
|
||||||
|
+ in unsigned long aFlags,
|
||||||
|
+ in nsresult aResult,
|
||||||
|
+ in nsISupports aSessionsState,
|
||||||
|
+ in nsISupports aContinuationState);
|
||||||
|
+
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
diff -up firefox-46.0.1/netwerk/protocol/http/nsHttpBasicAuth.cpp.890908-async-negotiate firefox-46.0.1/netwerk/protocol/http/nsHttpBasicAuth.cpp
|
||||||
|
--- firefox-46.0.1/netwerk/protocol/http/nsHttpBasicAuth.cpp.890908-async-negotiate 2016-05-03 07:31:08.000000000 +0200
|
||||||
|
+++ firefox-46.0.1/netwerk/protocol/http/nsHttpBasicAuth.cpp 2016-05-26 15:04:33.971068476 +0200
|
||||||
|
@@ -49,6 +49,20 @@ nsHttpBasicAuth::ChallengeReceived(nsIHt
|
||||||
|
*identityInvalid = true;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
+NS_IMETHODIMP
|
||||||
|
+nsHttpBasicAuth::GenerateCredentialsAsync(nsIHttpAuthenticableChannel *authChannel,
|
||||||
|
+ nsIHttpAuthenticatorCallback* aCallback,
|
||||||
|
+ const char *challenge,
|
||||||
|
+ bool isProxyAuth,
|
||||||
|
+ const char16_t *domain,
|
||||||
|
+ const char16_t *username,
|
||||||
|
+ const char16_t *password,
|
||||||
|
+ nsISupports *sessionState,
|
||||||
|
+ nsISupports *continuationState,
|
||||||
|
+ nsICancelable **aCancellable)
|
||||||
|
+{
|
||||||
|
+ return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
+}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsHttpBasicAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
|
||||||
|
diff -up firefox-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp.890908-async-negotiate firefox-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp
|
||||||
|
--- firefox-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp.890908-async-negotiate 2016-05-03 07:31:08.000000000 +0200
|
||||||
|
+++ firefox-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp 2016-05-26 15:04:33.972068475 +0200
|
||||||
|
@@ -267,6 +267,11 @@ nsHttpChannelAuthProvider::Cancel(nsresu
|
||||||
|
mAsyncPromptAuthCancelable->Cancel(status);
|
||||||
|
mAsyncPromptAuthCancelable = nullptr;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ if (mGenerateCredentialsCancelable) {
|
||||||
|
+ mGenerateCredentialsCancelable->Cancel(status);
|
||||||
|
+ mGenerateCredentialsCancelable = nullptr;
|
||||||
|
+ }
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -280,6 +285,11 @@ nsHttpChannelAuthProvider::Disconnect(ns
|
||||||
|
mAsyncPromptAuthCancelable = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (mGenerateCredentialsCancelable) {
|
||||||
|
+ mGenerateCredentialsCancelable->Cancel(status);
|
||||||
|
+ mGenerateCredentialsCancelable = nullptr;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
NS_IF_RELEASE(mProxyAuthContinuationState);
|
||||||
|
NS_IF_RELEASE(mAuthContinuationState);
|
||||||
|
|
||||||
|
@@ -355,11 +365,6 @@ nsHttpChannelAuthProvider::GenCredsAndSe
|
||||||
|
char **result)
|
||||||
|
{
|
||||||
|
nsresult rv;
|
||||||
|
- uint32_t authFlags;
|
||||||
|
-
|
||||||
|
- rv = auth->GetAuthFlags(&authFlags);
|
||||||
|
- if (NS_FAILED(rv)) return rv;
|
||||||
|
-
|
||||||
|
nsISupports *ss = sessionState;
|
||||||
|
|
||||||
|
// set informations that depend on whether
|
||||||
|
@@ -373,6 +378,22 @@ nsHttpChannelAuthProvider::GenCredsAndSe
|
||||||
|
continuationState = &mAuthContinuationState;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ rv = auth->GenerateCredentialsAsync(mAuthChannel,
|
||||||
|
+ this,
|
||||||
|
+ challenge,
|
||||||
|
+ proxyAuth,
|
||||||
|
+ ident.Domain(),
|
||||||
|
+ ident.User(),
|
||||||
|
+ ident.Password(),
|
||||||
|
+ ss,
|
||||||
|
+ *continuationState,
|
||||||
|
+ getter_AddRefs(mGenerateCredentialsCancelable));
|
||||||
|
+ if (NS_SUCCEEDED(rv)) {
|
||||||
|
+ // Calling generate credentials async, results will be dispatched to the
|
||||||
|
+ // main thread by calling OnCredsGenerated method
|
||||||
|
+ return NS_ERROR_IN_PROGRESS;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
uint32_t generateFlags;
|
||||||
|
rv = auth->GenerateCredentials(mAuthChannel,
|
||||||
|
challenge,
|
||||||
|
@@ -393,6 +414,29 @@ nsHttpChannelAuthProvider::GenCredsAndSe
|
||||||
|
LOG(("generated creds: %s\n", *result));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+ return UpdateCache(auth, scheme, host, port, directory, realm,
|
||||||
|
+ challenge, ident, *result, generateFlags, sessionState);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+nsresult
|
||||||
|
+nsHttpChannelAuthProvider::UpdateCache(nsIHttpAuthenticator *auth,
|
||||||
|
+ const char *scheme,
|
||||||
|
+ const char *host,
|
||||||
|
+ int32_t port,
|
||||||
|
+ const char *directory,
|
||||||
|
+ const char *realm,
|
||||||
|
+ const char *challenge,
|
||||||
|
+ const nsHttpAuthIdentity &ident,
|
||||||
|
+ const char *creds,
|
||||||
|
+ uint32_t generateFlags,
|
||||||
|
+ nsISupports *sessionState)
|
||||||
|
+{
|
||||||
|
+ nsresult rv;
|
||||||
|
+
|
||||||
|
+ uint32_t authFlags;
|
||||||
|
+ rv = auth->GetAuthFlags(&authFlags);
|
||||||
|
+ if (NS_FAILED(rv)) return rv;
|
||||||
|
+
|
||||||
|
// find out if this authenticator allows reuse of credentials and/or
|
||||||
|
// challenge.
|
||||||
|
bool saveCreds =
|
||||||
|
@@ -410,6 +454,7 @@ nsHttpChannelAuthProvider::GenCredsAndSe
|
||||||
|
nsAutoCString suffix;
|
||||||
|
GetOriginAttributesSuffix(chan, suffix);
|
||||||
|
|
||||||
|
+
|
||||||
|
// create a cache entry. we do this even though we don't yet know that
|
||||||
|
// these credentials are valid b/c we need to avoid prompting the user
|
||||||
|
// more than once in case the credentials are valid.
|
||||||
|
@@ -417,12 +462,13 @@ nsHttpChannelAuthProvider::GenCredsAndSe
|
||||||
|
// if the credentials are not reusable, then we don't bother sticking
|
||||||
|
// them in the auth cache.
|
||||||
|
rv = authCache->SetAuthEntry(scheme, host, port, directory, realm,
|
||||||
|
- saveCreds ? *result : nullptr,
|
||||||
|
+ saveCreds ? creds : nullptr,
|
||||||
|
saveChallenge ? challenge : nullptr,
|
||||||
|
suffix,
|
||||||
|
saveIdentity ? &ident : nullptr,
|
||||||
|
sessionState);
|
||||||
|
return rv;
|
||||||
|
+
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
@@ -1224,6 +1270,66 @@ NS_IMETHODIMP nsHttpChannelAuthProvider:
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
+nsHttpChannelAuthProvider::OnCredsGenerated(const char *aGeneratedCreds,
|
||||||
|
+ uint32_t aFlags,
|
||||||
|
+ nsresult aResult,
|
||||||
|
+ nsISupports* aSessionState,
|
||||||
|
+ nsISupports* aContinuationState)
|
||||||
|
+{
|
||||||
|
+ nsresult rv;
|
||||||
|
+
|
||||||
|
+ MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
+
|
||||||
|
+ // When channel is closed, do not proceed
|
||||||
|
+ if (!mAuthChannel) {
|
||||||
|
+ return NS_OK;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ mGenerateCredentialsCancelable = nullptr;
|
||||||
|
+
|
||||||
|
+ if (NS_FAILED(aResult)) {
|
||||||
|
+ return OnAuthCancelled(nullptr, true);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // We want to update m(Proxy)AuthContinuationState in case it was changed by
|
||||||
|
+ // nsHttpNegotiateAuth::GenerateCredentials
|
||||||
|
+ nsCOMPtr<nsISupports> contState(aContinuationState);
|
||||||
|
+ if (mProxyAuth) {
|
||||||
|
+ contState.swap(mProxyAuthContinuationState);
|
||||||
|
+ NS_IF_ADDREF(mProxyAuthContinuationState);
|
||||||
|
+ } else {
|
||||||
|
+ contState.swap(mAuthContinuationState);
|
||||||
|
+ NS_IF_ADDREF(mAuthContinuationState);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ nsCOMPtr<nsIHttpAuthenticator> auth;
|
||||||
|
+ nsAutoCString unused;
|
||||||
|
+ rv = GetAuthenticator(mCurrentChallenge.get(), unused, getter_AddRefs(auth));
|
||||||
|
+ NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
+
|
||||||
|
+ const char *host;
|
||||||
|
+ int32_t port;
|
||||||
|
+ nsHttpAuthIdentity *ident;
|
||||||
|
+ nsAutoCString directory, scheme;
|
||||||
|
+ nsISupports **unusedContinuationState;
|
||||||
|
+
|
||||||
|
+ // Get realm from challenge
|
||||||
|
+ nsAutoCString realm;
|
||||||
|
+ ParseRealm(mCurrentChallenge.get(), realm);
|
||||||
|
+
|
||||||
|
+ rv = GetAuthorizationMembers(mProxyAuth, scheme, host, port,
|
||||||
|
+ directory, ident, unusedContinuationState);
|
||||||
|
+ if (NS_FAILED(rv)) return rv;
|
||||||
|
+
|
||||||
|
+ UpdateCache(auth, scheme.get(), host, port, directory.get(), realm.get(),
|
||||||
|
+ mCurrentChallenge.get(), *ident, aGeneratedCreds, aFlags, aSessionState);
|
||||||
|
+ mCurrentChallenge.Truncate();
|
||||||
|
+
|
||||||
|
+ ContinueOnAuthAvailable(nsDependentCString(aGeneratedCreds));
|
||||||
|
+ return NS_OK;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+nsresult
|
||||||
|
nsHttpChannelAuthProvider::ContinueOnAuthAvailable(const nsCSubstring& creds)
|
||||||
|
{
|
||||||
|
nsresult rv;
|
||||||
|
@@ -1457,7 +1563,7 @@ nsHttpChannelAuthProvider::GetCurrentPat
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(nsHttpChannelAuthProvider, nsICancelable,
|
||||||
|
- nsIHttpChannelAuthProvider, nsIAuthPromptCallback)
|
||||||
|
+ nsIHttpChannelAuthProvider, nsIAuthPromptCallback, nsIHttpAuthenticatorCallback)
|
||||||
|
|
||||||
|
} // namespace net
|
||||||
|
} // namespace mozilla
|
||||||
|
diff -up firefox-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.h.890908-async-negotiate firefox-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.h
|
||||||
|
--- firefox-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.h.890908-async-negotiate 2016-05-03 07:31:08.000000000 +0200
|
||||||
|
+++ firefox-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.h 2016-05-26 15:04:33.972068475 +0200
|
||||||
|
@@ -9,11 +9,13 @@
|
||||||
|
|
||||||
|
#include "nsIHttpChannelAuthProvider.h"
|
||||||
|
#include "nsIAuthPromptCallback.h"
|
||||||
|
+#include "nsIHttpAuthenticatorCallback.h"
|
||||||
|
#include "nsString.h"
|
||||||
|
#include "nsCOMPtr.h"
|
||||||
|
#include "nsHttpAuthCache.h"
|
||||||
|
#include "nsProxyInfo.h"
|
||||||
|
#include "nsCRT.h"
|
||||||
|
+#include "nsICancelableRunnable.h"
|
||||||
|
|
||||||
|
class nsIHttpAuthenticableChannel;
|
||||||
|
class nsIHttpAuthenticator;
|
||||||
|
@@ -25,12 +27,14 @@ class nsHttpHandler;
|
||||||
|
|
||||||
|
class nsHttpChannelAuthProvider : public nsIHttpChannelAuthProvider
|
||||||
|
, public nsIAuthPromptCallback
|
||||||
|
+ , public nsIHttpAuthenticatorCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_NSICANCELABLE
|
||||||
|
NS_DECL_NSIHTTPCHANNELAUTHPROVIDER
|
||||||
|
NS_DECL_NSIAUTHPROMPTCALLBACK
|
||||||
|
+ NS_DECL_NSIHTTPAUTHENTICATORCALLBACK
|
||||||
|
|
||||||
|
nsHttpChannelAuthProvider();
|
||||||
|
static void InitializePrefs();
|
||||||
|
@@ -117,6 +121,19 @@ private:
|
||||||
|
// For more details look at the bug 647010.
|
||||||
|
bool BlockPrompt();
|
||||||
|
|
||||||
|
+ // Store credentials to the cache when appropriate aFlags are set.
|
||||||
|
+ nsresult UpdateCache(nsIHttpAuthenticator *aAuth,
|
||||||
|
+ const char *aScheme,
|
||||||
|
+ const char *aHost,
|
||||||
|
+ int32_t aPort,
|
||||||
|
+ const char *aDirectory,
|
||||||
|
+ const char *aRealm,
|
||||||
|
+ const char *aChallenge,
|
||||||
|
+ const nsHttpAuthIdentity &aIdent,
|
||||||
|
+ const char *aCreds,
|
||||||
|
+ uint32_t aGenerateFlags,
|
||||||
|
+ nsISupports *aSessionState);
|
||||||
|
+
|
||||||
|
private:
|
||||||
|
nsIHttpAuthenticableChannel *mAuthChannel; // weak ref
|
||||||
|
|
||||||
|
@@ -160,6 +177,7 @@ private:
|
||||||
|
// authentication credentials dialogs for sub-resources and cross-origin
|
||||||
|
// sub-resources.
|
||||||
|
static uint32_t sAuthAllowPref;
|
||||||
|
+ nsCOMPtr<nsICancelable> mGenerateCredentialsCancelable;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace net
|
||||||
|
diff -up firefox-46.0.1/netwerk/protocol/http/nsHttpDigestAuth.cpp.890908-async-negotiate firefox-46.0.1/netwerk/protocol/http/nsHttpDigestAuth.cpp
|
||||||
|
--- firefox-46.0.1/netwerk/protocol/http/nsHttpDigestAuth.cpp.890908-async-negotiate 2016-05-03 07:31:08.000000000 +0200
|
||||||
|
+++ firefox-46.0.1/netwerk/protocol/http/nsHttpDigestAuth.cpp 2016-05-26 15:04:33.972068475 +0200
|
||||||
|
@@ -158,6 +158,22 @@ nsHttpDigestAuth::ChallengeReceived(nsIH
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
+
|
||||||
|
+NS_IMETHODIMP
|
||||||
|
+nsHttpDigestAuth::GenerateCredentialsAsync(nsIHttpAuthenticableChannel *authChannel,
|
||||||
|
+ nsIHttpAuthenticatorCallback* aCallback,
|
||||||
|
+ const char *challenge,
|
||||||
|
+ bool isProxyAuth,
|
||||||
|
+ const char16_t *domain,
|
||||||
|
+ const char16_t *username,
|
||||||
|
+ const char16_t *password,
|
||||||
|
+ nsISupports *sessionState,
|
||||||
|
+ nsISupports *continuationState,
|
||||||
|
+ nsICancelable **aCancellable)
|
||||||
|
+{
|
||||||
|
+ return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsHttpDigestAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
|
||||||
|
const char *challenge,
|
||||||
|
diff -up firefox-46.0.1/netwerk/protocol/http/nsHttpNTLMAuth.cpp.890908-async-negotiate firefox-46.0.1/netwerk/protocol/http/nsHttpNTLMAuth.cpp
|
||||||
|
--- firefox-46.0.1/netwerk/protocol/http/nsHttpNTLMAuth.cpp.890908-async-negotiate 2016-05-03 07:31:08.000000000 +0200
|
||||||
|
+++ firefox-46.0.1/netwerk/protocol/http/nsHttpNTLMAuth.cpp 2016-05-26 15:04:33.972068475 +0200
|
||||||
|
@@ -323,6 +323,21 @@ nsHttpNTLMAuth::ChallengeReceived(nsIHtt
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
+nsHttpNTLMAuth::GenerateCredentialsAsync(nsIHttpAuthenticableChannel *authChannel,
|
||||||
|
+ nsIHttpAuthenticatorCallback* aCallback,
|
||||||
|
+ const char *challenge,
|
||||||
|
+ bool isProxyAuth,
|
||||||
|
+ const char16_t *domain,
|
||||||
|
+ const char16_t *username,
|
||||||
|
+ const char16_t *password,
|
||||||
|
+ nsISupports *sessionState,
|
||||||
|
+ nsISupports *continuationState,
|
||||||
|
+ nsICancelable **aCancellable)
|
||||||
|
+{
|
||||||
|
+ return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+NS_IMETHODIMP
|
||||||
|
nsHttpNTLMAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
|
||||||
|
const char *challenge,
|
||||||
|
bool isProxyAuth,
|
||||||
|
diff -up firefox-46.0.1/netwerk/protocol/http/nsIHttpAuthenticator.idl.890908-async-negotiate firefox-46.0.1/netwerk/protocol/http/nsIHttpAuthenticator.idl
|
||||||
|
--- firefox-46.0.1/netwerk/protocol/http/nsIHttpAuthenticator.idl.890908-async-negotiate 2016-05-03 07:31:08.000000000 +0200
|
||||||
|
+++ firefox-46.0.1/netwerk/protocol/http/nsIHttpAuthenticator.idl 2016-05-26 15:04:33.973068475 +0200
|
||||||
|
@@ -6,6 +6,8 @@
|
||||||
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
|
interface nsIHttpAuthenticableChannel;
|
||||||
|
+interface nsIHttpAuthenticatorCallback;
|
||||||
|
+interface nsICancelable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nsIHttpAuthenticator
|
||||||
|
@@ -18,7 +20,7 @@ interface nsIHttpAuthenticableChannel;
|
||||||
|
* where <auth-scheme> is the lower-cased value of the authentication scheme
|
||||||
|
* found in the server challenge per the rules of RFC 2617.
|
||||||
|
*/
|
||||||
|
-[scriptable, uuid(16784db0-fcb1-4352-b0c9-6a3a67e3cf79)]
|
||||||
|
+[scriptable, uuid(fef7db8a-a4e2-49d1-9685-19ed7e309b7d)]
|
||||||
|
interface nsIHttpAuthenticator : nsISupports
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
@@ -54,6 +56,54 @@ interface nsIHttpAuthenticator : nsISupp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to generate the authentication credentials for a particular
|
||||||
|
+ * server/proxy challenge asynchronously. Credentials will be sent back
|
||||||
|
+ * to the server via an Authorization/Proxy-Authorization header.
|
||||||
|
+ *
|
||||||
|
+ * @param aChannel
|
||||||
|
+ * the http channel requesting credentials
|
||||||
|
+ * @param aCallback
|
||||||
|
+ * callback function to be called when credentials are available
|
||||||
|
+ * @param aChallenge
|
||||||
|
+ * the challenge from the WWW-Authenticate/Proxy-Authenticate
|
||||||
|
+ * server response header. (possibly from the auth cache.)
|
||||||
|
+ * @param aProxyAuth
|
||||||
|
+ * flag indicating whether or not aChallenge is from a proxy.
|
||||||
|
+ * @param aDomain
|
||||||
|
+ * string containing the domain name (if appropriate)
|
||||||
|
+ * @param aUser
|
||||||
|
+ * string containing the user name
|
||||||
|
+ * @param aPassword
|
||||||
|
+ * string containing the password
|
||||||
|
+ * @param aSessionState
|
||||||
|
+ * state stored along side the user's identity in the auth cache
|
||||||
|
+ * for the lifetime of the browser session. if a new auth cache
|
||||||
|
+ * entry is created for this challenge, then this parameter will
|
||||||
|
+ * be null. on return, the result will be stored in the new auth
|
||||||
|
+ * cache entry. this parameter is non-null when an auth cache entry
|
||||||
|
+ * is being reused. currently modification of session state is not
|
||||||
|
+ * communicated to caller, thus caching credentials obtained by
|
||||||
|
+ * asynchronous way is not supported.
|
||||||
|
+ * @param aContinuationState
|
||||||
|
+ * state held by the channel between consecutive calls to
|
||||||
|
+ * generateCredentials, assuming multiple calls are required
|
||||||
|
+ * to authenticate. this state is held for at most the lifetime of
|
||||||
|
+ * the channel.
|
||||||
|
+ * @pram aCancel
|
||||||
|
+ * returns cancellable runnable object which caller can use to cancel
|
||||||
|
+ * calling aCallback when finished.
|
||||||
|
+ */
|
||||||
|
+ void generateCredentialsAsync(in nsIHttpAuthenticableChannel aChannel,
|
||||||
|
+ in nsIHttpAuthenticatorCallback aCallback,
|
||||||
|
+ in string aChallenge,
|
||||||
|
+ in boolean aProxyAuth,
|
||||||
|
+ in wstring aDomain,
|
||||||
|
+ in wstring aUser,
|
||||||
|
+ in wstring aPassword,
|
||||||
|
+ in nsISupports aSessionState,
|
||||||
|
+ in nsISupports aContinuationState,
|
||||||
|
+ out nsICancelable aCancel);
|
||||||
|
+ /**
|
||||||
|
+ * Called to generate the authentication credentials for a particular
|
||||||
|
* server/proxy challenge. This is the value that will be sent back
|
||||||
|
* to the server via an Authorization/Proxy-Authorization header.
|
||||||
|
*
|
Loading…
Reference in New Issue
Block a user