/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
* copy, modify, and distribute this software in source code or binary form for use
* in connection with the web services and APIs provided by Facebook.
*
* As with any software that integrates with the Facebook platform, your use of
* this software is subject to the Facebook Developer Principles and Policies
* [http://developers.facebook.com/policy/]. This copyright notice shall be
* included in all copies or substantial portions of the software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.facebook.login;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Parcel;
import android.text.TextUtils;
import android.webkit.CookieSyncManager;
import com.facebook.AccessToken;
import com.facebook.AccessTokenSource;
import com.facebook.FacebookException;
import com.facebook.FacebookOperationCanceledException;
import com.facebook.FacebookRequestError;
import com.facebook.FacebookSdk;
import com.facebook.FacebookServiceException;
import com.facebook.appevents.AppEventsConstants;
import com.facebook.internal.ServerProtocol;
import com.facebook.internal.Utility;
import java.util.Locale;
abstract class WebLoginMethodHandler extends LoginMethodHandler {
private static final String WEB_VIEW_AUTH_HANDLER_STORE =
"com.facebook.login.AuthorizationClient.WebViewAuthHandler.TOKEN_STORE_KEY";
private static final String WEB_VIEW_AUTH_HANDLER_TOKEN_KEY = "TOKEN";
private static final String getRedirectUri() {
return "fb" + FacebookSdk.getApplicationId() + "://authorize";
}
private String e2e;
WebLoginMethodHandler(LoginClient loginClient) {
super(loginClient);
}
WebLoginMethodHandler(Parcel source) {
super(source);
}
abstract AccessTokenSource getTokenSource();
protected String getSSODevice() {
return null;
}
protected Bundle getParameters(final LoginClient.Request request) {
Bundle parameters = new Bundle();
if (!Utility.isNullOrEmpty(request.getPermissions())) {
String scope = TextUtils.join(",", request.getPermissions());
parameters.putString(ServerProtocol.DIALOG_PARAM_SCOPE, scope);
addLoggingExtra(ServerProtocol.DIALOG_PARAM_SCOPE, scope);
}
DefaultAudience audience = request.getDefaultAudience();
parameters.putString(
ServerProtocol.DIALOG_PARAM_DEFAULT_AUDIENCE, audience.getNativeProtocolAudience());
parameters.putString(
ServerProtocol.DIALOG_PARAM_STATE, getClientState(request.getAuthId()));
AccessToken previousToken = AccessToken.getCurrentAccessToken();
String previousTokenString = previousToken != null ? previousToken.getToken() : null;
if (previousTokenString != null
&& (previousTokenString.equals(loadCookieToken()))) {
parameters.putString(
ServerProtocol.DIALOG_PARAM_ACCESS_TOKEN,
previousTokenString);
// Don't log the actual access token, just its presence or absence.
addLoggingExtra(
ServerProtocol.DIALOG_PARAM_ACCESS_TOKEN,
AppEventsConstants.EVENT_PARAM_VALUE_YES);
} else {
// The call to clear cookies will create the first instance of CookieSyncManager if
// necessary
Utility.clearFacebookCookies(loginClient.getActivity());
addLoggingExtra(
ServerProtocol.DIALOG_PARAM_ACCESS_TOKEN,
AppEventsConstants.EVENT_PARAM_VALUE_NO);
}
return parameters;
}
protected Bundle addExtraParameters(Bundle parameters, final LoginClient.Request request) {
parameters.putString(ServerProtocol.DIALOG_PARAM_REDIRECT_URI, getRedirectUri());
parameters.putString(ServerProtocol.DIALOG_PARAM_CLIENT_ID, request.getApplicationId());
parameters.putString(ServerProtocol.DIALOG_PARAM_E2E, loginClient.getE2E());
parameters.putString(
ServerProtocol.DIALOG_PARAM_RESPONSE_TYPE,
ServerProtocol.DIALOG_RESPONSE_TYPE_TOKEN_AND_SIGNED_REQUEST);
parameters.putString(
ServerProtocol.DIALOG_PARAM_RETURN_SCOPES,
ServerProtocol.DIALOG_RETURN_SCOPES_TRUE);
parameters.putString(
ServerProtocol.DIALOG_PARAM_AUTH_TYPE,
ServerProtocol.DIALOG_REREQUEST_AUTH_TYPE);
if (getSSODevice() != null) {
parameters.putString(ServerProtocol.DIALOG_PARAM_SSO_DEVICE, getSSODevice());
}
return parameters;
}
protected void onComplete(LoginClient.Request request, Bundle values, FacebookException error) {
LoginClient.Result outcome;
e2e = null;
if (values != null) {
// Actual e2e we got from the dialog should be used for logging.
if (values.containsKey(ServerProtocol.DIALOG_PARAM_E2E)) {
e2e = values.getString(ServerProtocol.DIALOG_PARAM_E2E);
}
try {
AccessToken token = createAccessTokenFromWebBundle(
request.getPermissions(),
values,
getTokenSource(),
request.getApplicationId());
outcome = LoginClient.Result.createTokenResult(
loginClient.getPendingRequest(),
token);
// Ensure any cookies set by the dialog are saved
// This is to work around a bug where CookieManager may fail to instantiate if
// CookieSyncManager has never been created.
CookieSyncManager syncManager =
CookieSyncManager.createInstance(loginClient.getActivity());
syncManager.sync();
saveCookieToken(token.getToken());
} catch (FacebookException ex) {
outcome = LoginClient.Result.createErrorResult(
loginClient.getPendingRequest(),
null,
ex.getMessage());
}
} else {
if (error instanceof FacebookOperationCanceledException) {
outcome = LoginClient.Result.createCancelResult(loginClient.getPendingRequest(),
"User canceled log in.");
} else {
// Something went wrong, don't log a completion event since it will skew timing
// results.
e2e = null;
String errorCode = null;
String errorMessage = error.getMessage();
if (error instanceof FacebookServiceException) {
FacebookRequestError requestError =
((FacebookServiceException)error).getRequestError();
errorCode = String.format(Locale.ROOT, "%d", requestError.getErrorCode());
errorMessage = requestError.toString();
}
outcome = LoginClient.Result.createErrorResult(loginClient.getPendingRequest(),
null, errorMessage, errorCode);
}
}
if (!Utility.isNullOrEmpty(e2e)) {
logWebLoginCompleted(e2e);
}
loginClient.completeAndValidate(outcome);
}
private String loadCookieToken() {
Context context = loginClient.getActivity();
SharedPreferences sharedPreferences = context.getSharedPreferences(
WEB_VIEW_AUTH_HANDLER_STORE,
Context.MODE_PRIVATE);
return sharedPreferences.getString(WEB_VIEW_AUTH_HANDLER_TOKEN_KEY, "");
}
private void saveCookieToken(String token) {
Context context = loginClient.getActivity();
context.getSharedPreferences(
WEB_VIEW_AUTH_HANDLER_STORE,
Context.MODE_PRIVATE)
.edit()
.putString(WEB_VIEW_AUTH_HANDLER_TOKEN_KEY, token)
.apply();
}
}