001package com.gigya.android.sdk.providers.provider;
002
003import android.app.Activity;
004import android.content.Context;
005import android.util.Pair;
006
007import com.gigya.android.sdk.Config;
008import com.gigya.android.sdk.Gigya;
009import com.gigya.android.sdk.GigyaLogger;
010import com.gigya.android.sdk.account.IAccountService;
011import com.gigya.android.sdk.api.GigyaApiResponse;
012import com.gigya.android.sdk.api.IBusinessApiService;
013import com.gigya.android.sdk.network.adapter.RestAdapter;
014import com.gigya.android.sdk.persistence.IPersistenceService;
015import com.gigya.android.sdk.session.ISessionService;
016import com.gigya.android.sdk.session.SessionInfo;
017import com.gigya.android.sdk.ui.WebLoginActivity;
018import com.gigya.android.sdk.utils.AuthUtils;
019import com.gigya.android.sdk.utils.UrlUtils;
020
021import org.json.JSONObject;
022
023import java.util.Map;
024import java.util.TreeMap;
025
026public class WebLoginProvider extends Provider {
027
028    private static final String LOG_TAG = "WebLoginProvider";
029
030    final private ISessionService _sessionService;
031    final private IAccountService _accountService;
032    final private Config _config;
033
034    public WebLoginProvider(Context context,
035                            Config config,
036                            ISessionService sessionService,
037                            IAccountService accountService,
038                            IPersistenceService persistenceService,
039                            IBusinessApiService businessApiService,
040                            ProviderCallback providerCallback) {
041        super(context, persistenceService, businessApiService, providerCallback);
042        _config = config;
043        _sessionService = sessionService;
044        _accountService = accountService;
045    }
046
047    @Override
048    public String getName() {
049        return "web";
050    }
051
052    @Override
053    public void login(Map<String, Object> loginParams, final String loginMode) {
054        if (_connecting) {
055            return;
056        }
057        _connecting = true;
058        _loginMode = loginMode;
059        final String providerName = (String) loginParams.get("provider");
060        final String loginUrl = getRequest(_context, loginParams, loginMode);
061        WebLoginActivity.present(_context, loginUrl, new WebLoginActivity.WebLoginActivityCallback() {
062
063            @Override
064            public void onResult(Activity activity, Map<String, Object> parsed) {
065                GigyaLogger.debug(LOG_TAG, "onResult: " + parsed.toString());
066
067                final String status = (String) parsed.get("status");
068                if (status != null && status.equals("ok")) {
069
070                    final SessionInfo sessionInfo = parseSessionInfo(parsed);
071                    // Notify successful sign in.
072                    onLoginSuccess(providerName, sessionInfo);
073                    
074                } else {
075
076                    JSONObject jsonObject = new JSONObject();
077
078                    try {
079                        // An error result appears in a different format.
080                        // Need to parse it correctly in order for the flow to continue as expected.
081
082                        if (parsed.containsKey("error_description")) {
083
084                            final String errorDescription = (String) parsed.get("error_description");
085                            if (errorDescription != null) {
086                                String[] parts = errorDescription.replace("+", "").split("-");
087                                if (parts.length > 1) {
088                                    final int errorCode = Integer.parseInt(parts[0].trim());
089                                    final String errorMessage = parts[1].trim();
090
091                                    jsonObject.put("errorCode", errorCode);
092                                    jsonObject.put("errorMessage", errorMessage);
093                                }
094                            }
095
096                            if (parsed.containsKey("x_regToken")) {
097                                final String regToken = (String) parsed.get("x_regToken");
098                                jsonObject.put("regToken", regToken); // Nullification is not relevant here.
099                            }
100                        }
101                    } catch (Exception ex) {
102                        ex.printStackTrace();
103                    }
104
105                    GigyaLogger.debug(LOG_TAG, "onResult: with error = " + jsonObject.toString());
106
107                    onLoginFailed(new GigyaApiResponse(jsonObject.toString()));
108                }
109
110                if (activity != null) {
111                    activity.finish();
112                }
113            }
114
115            @Override
116            public void onCancelled() {
117                if (_providerCallback != null) {
118                    _providerCallback.onCanceled();
119                }
120            }
121        });
122    }
123
124    @Override
125    public void logout() {
126        // Stub.
127    }
128
129    @Override
130    public String getProviderSessions(String tokenOrCode, long expiration, String uid) {
131        return null;
132    }
133
134    @Override
135    public boolean supportsTokenTracking() {
136        return false;
137    }
138
139    @Override
140    public void trackTokenChange() {
141        // Stub.
142    }
143
144    private SessionInfo parseSessionInfo(Map<String, Object> result) {
145        final String accessToken = (String) result.get("access_token");
146        final String expiresInString = (String) result.get("expires_in");
147        final long expiresIn = Long.parseLong(expiresInString != null ? expiresInString : "0");
148        final String secret = (String) result.get("x_access_token_secret");
149        return new SessionInfo(secret, accessToken, expiresIn);
150    }
151
152    private String getRequest(Context context, Map<String, Object> loginParams, String loginMode) {
153        final TreeMap<String, Object> serverParams = new TreeMap<>();
154        final String provider = ((String) loginParams.get("provider"));
155        if (provider != null) {
156            provider.toLowerCase();
157            final String xperm = (String) loginParams.get(provider + "ExtraPermissions");
158            if (xperm != null) {
159                loginParams.remove(provider + "ExtraPermissions");
160                serverParams.put("x_extraPermissions", xperm);
161            }
162        }
163        // Deep link schematics -> Scheme = gigya, host = gsapi, pathPrefix = package name + "/login_result.
164        final String redirectUri = "gigya://gsapi/" + context.getPackageName() + "/login_result";
165        serverParams.put("redirect_uri", redirectUri);
166        serverParams.put("response_type", "token");
167        serverParams.put("client_id", _config.getApiKey());
168        serverParams.put("gmid", _config.getGmid());
169        serverParams.put("ucid", _config.getUcid());
170        serverParams.put("x_secret_type", "oauth1");
171        serverParams.put("x_sdk", Gigya.VERSION);
172        // x_params additions.
173        for (Map.Entry entry : loginParams.entrySet()) {
174            final String key = (String) entry.getKey();
175            Object value = loginParams.get(key);
176            if (value != null) {
177                if (key.startsWith("x_"))
178                    serverParams.put(key, value);
179                else
180                    serverParams.put("x_" + key, value);
181            }
182        }
183
184        String api = "socialize.login";
185        if (loginMode.equals("connect")) {
186            api = "socialize.addConnection";
187        }
188
189        if (_sessionService.isValid()) {
190            // Add signature parameters if needed.
191            @SuppressWarnings("ConstantConditions") final String sessionToken = _sessionService.getSession().getSessionToken();
192            serverParams.put("oauth_token", sessionToken);
193            final String sessionSecret = _sessionService.getSession().getSessionSecret();
194            AuthUtils.addAuthenticationParameters(sessionSecret,
195                    RestAdapter.GET,
196                    UrlUtils.getBaseUrl(api, _config.getApiDomain()),
197                    serverParams,
198                    _config.getServerOffset());
199        }
200
201
202        // Build final URL.
203        return String.format("%s://%s.%s/%s?%s", "https", "socialize", _config.getApiDomain(),
204                api, UrlUtils.buildEncodedQuery(serverParams));
205    }
206
207    private Pair<String, String> getPostRequest(Map<String, Object> loginParams) {
208        /* Remove if added. */
209        if (!loginParams.isEmpty())
210            loginParams.remove(FacebookProvider.LOGIN_BEHAVIOUR);
211
212        final String url = "https://socialize." + _config.getApiDomain() + "/socialize.login";
213        final TreeMap<String, Object> urlParams = new TreeMap<>();
214        urlParams.put("redirect_uri", "gsapi://login_result");
215        urlParams.put("response_type", "token");
216        urlParams.put("client_id", _config.getApiKey());
217        urlParams.put("gmid", _config.getGmid());
218        urlParams.put("ucid", _config.getUcid());
219
220        // x_params additions.
221        for (Map.Entry entry : loginParams.entrySet()) {
222            final String key = (String) entry.getKey();
223            Object value = loginParams.get(key);
224            if (value != null) {
225                if (key.startsWith("x_"))
226                    urlParams.put(key, value);
227                else
228                    urlParams.put("x_" + key, value);
229            }
230        }
231        urlParams.put("x_secret_type", "oauth1");
232        urlParams.put("x_endPoint", "socialize.login");
233        urlParams.put("x_sdk", Gigya.VERSION);
234        final String provider = (String) loginParams.get("provider");
235        if (provider != null) {
236            urlParams.put("x_provider", provider);
237        }
238
239        // Encode post body.
240        final String encodedParams = UrlUtils.buildEncodedQuery(urlParams);
241        return new Pair<>(url, encodedParams);
242    }
243}