/**
* 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.Intent;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Base64;
import android.util.Log;
import com.facebook.AccessToken;
import com.facebook.AccessTokenSource;
import com.facebook.FacebookException;
import com.facebook.appevents.AppEventsLogger;
import com.facebook.internal.AnalyticsEvents;
import com.facebook.internal.NativeProtocol;
import com.facebook.internal.Utility;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
abstract class LoginMethodHandler implements Parcelable {
Map<String, String> methodLoggingExtras;
protected LoginClient loginClient;
LoginMethodHandler(LoginClient loginClient) {
this.loginClient = loginClient;
}
LoginMethodHandler(Parcel source) {
methodLoggingExtras = Utility.readStringMapFromParcel(source);
}
// This should only be used if restoring from a Parcel
void setLoginClient(LoginClient loginClient) {
if (this.loginClient != null) {
throw new FacebookException("Can't set LoginClient if it is already set.");
}
this.loginClient = loginClient;
}
abstract boolean tryAuthorize(LoginClient.Request request);
abstract String getNameForLogging();
boolean onActivityResult(int requestCode, int resultCode, Intent data) {
return false;
}
boolean needsInternetPermission() {
return false;
}
void cancel() {
}
void putChallengeParam(JSONObject param) throws JSONException {
}
protected String getClientState(String authId) {
JSONObject param = new JSONObject();
try {
param.put(LoginLogger.EVENT_PARAM_AUTH_LOGGER_ID, authId);
param.put(LoginLogger.EVENT_PARAM_METHOD, getNameForLogging());
putChallengeParam(param);
} catch (JSONException e) {
Log.w("LoginMethodHandler", "Error creating client state json: " + e.getMessage());
}
return param.toString();
}
protected void addLoggingExtra(String key, Object value) {
if (methodLoggingExtras == null) {
methodLoggingExtras = new HashMap<String, String>();
}
methodLoggingExtras.put(key, value == null ? null : value.toString());
}
protected void logWebLoginCompleted(String e2e) {
String applicationId = loginClient.getPendingRequest().getApplicationId();
AppEventsLogger appEventsLogger =
AppEventsLogger.newLogger(loginClient.getActivity(), applicationId);
Bundle parameters = new Bundle();
parameters.putString(AnalyticsEvents.PARAMETER_WEB_LOGIN_E2E, e2e);
parameters.putLong(
AnalyticsEvents.PARAMETER_WEB_LOGIN_SWITCHBACK_TIME, System.currentTimeMillis());
parameters.putString(AnalyticsEvents.PARAMETER_APP_ID, applicationId);
appEventsLogger.logSdkEvent(AnalyticsEvents.EVENT_WEB_LOGIN_COMPLETE, null, parameters);
}
static AccessToken createAccessTokenFromNativeLogin(
Bundle bundle,
AccessTokenSource source,
String applicationId) {
Date expires = Utility.getBundleLongAsDate(
bundle, NativeProtocol.EXTRA_EXPIRES_SECONDS_SINCE_EPOCH, new Date(0));
ArrayList<String> permissions = bundle.getStringArrayList(NativeProtocol.EXTRA_PERMISSIONS);
String token = bundle.getString(NativeProtocol.EXTRA_ACCESS_TOKEN);
if (Utility.isNullOrEmpty(token)) {
return null;
}
String userId = bundle.getString(NativeProtocol.EXTRA_USER_ID);
return new AccessToken(
token,
applicationId,
userId,
permissions,
null,
source,
expires,
new Date());
}
public static AccessToken createAccessTokenFromWebBundle(
Collection<String> requestedPermissions,
Bundle bundle,
AccessTokenSource source,
String applicationId) throws FacebookException {
Date expires = Utility.getBundleLongAsDate(bundle, AccessToken.EXPIRES_IN_KEY, new Date());
String token = bundle.getString(AccessToken.ACCESS_TOKEN_KEY);
// With Login v4, we now get back the actual permissions granted, so update the permissions
// to be the real thing
String grantedPermissions = bundle.getString("granted_scopes");
if (!Utility.isNullOrEmpty(grantedPermissions)) {
requestedPermissions = new ArrayList<String>(
Arrays.asList(grantedPermissions.split(",")));
}
String deniedPermissions = bundle.getString("denied_scopes");
List<String> declinedPermissions = null;
if (!Utility.isNullOrEmpty(deniedPermissions)) {
declinedPermissions = new ArrayList<String>(
Arrays.asList(deniedPermissions.split(",")));
}
if (Utility.isNullOrEmpty(token)) {
return null;
}
String signed_request = bundle.getString("signed_request");
String userId = getUserIDFromSignedRequest(signed_request);
return new AccessToken(
token,
applicationId,
userId,
requestedPermissions,
declinedPermissions,
source,
expires,
new Date());
}
static String getUserIDFromSignedRequest(
String signedRequest) throws FacebookException {
if (signedRequest == null || signedRequest.isEmpty()) {
throw new FacebookException(
"Authorization response does not contain the signed_request");
}
try {
String[] signatureAndPayload = signedRequest.split("\\.");
if (signatureAndPayload.length == 2) {
byte[] data = Base64.decode(signatureAndPayload[1], Base64.DEFAULT);
String dataStr = new String(data, "UTF-8");
JSONObject jsonObject = new JSONObject(dataStr);
return jsonObject.getString("user_id");
}
} catch (UnsupportedEncodingException ex) {
} catch (JSONException ex) {
}
throw new FacebookException("Failed to retrieve user_id from signed_request");
}
@Override
public void writeToParcel(Parcel dest, int flags) {
Utility.writeStringMapToParcel(dest, methodLoggingExtras);
}
}