· 9 years ago · Mar 01, 2016, 07:18 PM
1package com.skinseller.bot;
2
3import org.apache.commons.codec.binary.Base64;
4import org.apache.http.NameValuePair;
5import org.apache.http.client.CookieStore;
6import org.apache.http.cookie.Cookie;
7import org.apache.http.impl.client.BasicCookieStore;
8import org.apache.http.impl.cookie.BasicClientCookie;
9import org.apache.http.message.BasicNameValuePair;
10import org.json.simple.JSONObject;
11import org.json.simple.parser.JSONParser;
12import org.json.simple.parser.ParseException;
13
14import javax.crypto.BadPaddingException;
15import javax.crypto.Cipher;
16import javax.crypto.IllegalBlockSizeException;
17import javax.crypto.NoSuchPaddingException;
18import java.io.IOException;
19import java.math.BigInteger;
20import java.nio.charset.StandardCharsets;
21import java.security.InvalidKeyException;
22import java.security.KeyFactory;
23import java.security.NoSuchAlgorithmException;
24import java.security.PublicKey;
25import java.security.spec.InvalidKeySpecException;
26import java.security.spec.RSAPublicKeySpec;
27import java.time.Instant;
28import java.util.ArrayList;
29import java.util.Collections;
30import java.util.List;
31
32/**
33 * Created by Denis on 02.01.2016.
34 */
35public class UserLogin {
36 private String userName;
37 private String password;
38 private long steamID;
39
40 private boolean requiresCaptcha;
41 private String captchaGID = null;
42 private String captchaText = null;
43
44 private boolean requiresEmail;
45 private String emailDomain = null;
46 private String emailCode = null;
47
48 private boolean requires2FA;
49 private String twoFactorCode = null;
50
51 private SessionData session = null;
52 private boolean loggedIn = false;
53
54 private CookieStore cookies = new BasicCookieStore();
55
56 public UserLogin(String userName, String password) {
57 this.userName = userName;
58 this.password = password;
59 }
60
61 public LoginResult doLogin() throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {
62
63 if (cookies.getCookies().size() == 0) {
64 cookies.addCookie(createCookie("mobileClientVersion", "0 (2.1.3)", "/", ".steamcommunity.com"));
65 cookies.addCookie(createCookie("mobileClient", "android", "/", ".steamcommunity.com"));
66 cookies.addCookie(createCookie("Steam_Language", "english", "/", ".steamcommunity.com"));
67
68 List<NameValuePair> headers = new ArrayList<>();
69 headers.add(new BasicNameValuePair("X-Requested-With", "com.valvesoftware.android.steam.community"));
70 SteamWeb.mobileLoginRequest("https://steamcommunity.com/login?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client", "GET", Collections.emptyList(), cookies, headers);
71 }
72
73 List<NameValuePair> postData = new ArrayList<>();
74 postData.add(new BasicNameValuePair("username", this.userName));
75
76 String response = SteamWeb.mobileLoginRequest(APIEndpoints.COMMUNITY_BASE + "/login/getrsakey", "POST", postData, cookies, Collections.emptyList());
77 if (response == null || response.contains("<BODY>\nAn error occurred while processing your request.")) {
78 return LoginResult.GeneralFailure;
79 }
80
81 RSAResponse rsaResponse = RSAResponse.parseRSA(response);
82 if (rsaResponse == null || !rsaResponse.success) {
83 return LoginResult.BadRSA;
84 }
85
86 String encryptedPassword = encryptPassword(rsaResponse);
87
88 postData.clear();
89
90 postData.add(new BasicNameValuePair("username", userName));
91 postData.add(new BasicNameValuePair("password", encryptedPassword));
92
93 postData.add(new BasicNameValuePair("twofactorcode", twoFactorCode != null ? twoFactorCode : ""));
94
95 postData.add(new BasicNameValuePair("captchagid", requiresCaptcha ? captchaGID : "-1"));
96 postData.add(new BasicNameValuePair("captcha_text", requiresCaptcha ? captchaText : ""));
97
98 postData.add(new BasicNameValuePair("emailsteamid", (requires2FA || requiresEmail) ? Long.toString(steamID) : ""));
99 postData.add(new BasicNameValuePair("emailauth", requiresEmail ? emailCode : ""));
100
101 postData.add(new BasicNameValuePair("rsatimestamp", rsaResponse.timestamp));
102 postData.add(new BasicNameValuePair("remember_login", "false"));
103 postData.add(new BasicNameValuePair("oauth_client_id", "DE45CD61"));
104 postData.add(new BasicNameValuePair("oauth_scope", "read_profile write_profile read_client write_client"));
105 postData.add(new BasicNameValuePair("loginfriendlyname", "#login_emailauth_friendlyname_mobile"));
106 postData.add(new BasicNameValuePair("donotcache", Long.toString(Instant.now().getEpochSecond())));
107
108 response = SteamWeb.mobileLoginRequest(APIEndpoints.COMMUNITY_BASE + "/login/dologin", "POST", postData, cookies, Collections.emptyList());
109 if (response == null) {
110 return LoginResult.GeneralFailure;
111 }
112
113 LoginResponse loginResponse = LoginResponse.parseLoginResponse(response);
114
115 if (loginResponse != null && loginResponse.message != null && loginResponse.message.contains("Incorrect login")) {
116 return LoginResult.BadCredentials;
117 }
118
119 if (loginResponse.captchaNeeded) {
120 this.requiresCaptcha = true;
121 this.captchaGID = loginResponse.captchaGID;
122 return LoginResult.NeedCaptcha;
123 }
124
125 if (loginResponse.emailAuthNeeded) {
126 this.requiresEmail = true;
127 this.steamID = loginResponse.emailSteamID;
128 return LoginResult.NeedEmail;
129 }
130
131 if (loginResponse.twoFactorNeeded && !loginResponse.success) {
132 this.requires2FA = true;
133 return LoginResult.Need2FA;
134 }
135
136 if (loginResponse.message != null && loginResponse.message.contains("too many login failures")) {
137 return LoginResult.TooManyFailedLogins;
138 }
139
140 if (loginResponse.getOAuthData() == null || loginResponse.getOAuthData().oAuthToken == null || loginResponse.getOAuthData().oAuthToken.length() == 0) {
141 return LoginResult.GeneralFailure;
142 }
143
144 if (!loginResponse.loginComplete) {
145 return LoginResult.BadCredentials;
146 } else {
147 OAuth oAuthData = loginResponse.getOAuthData();
148 SessionData session = new SessionData();
149
150 session.setoAuthToken(oAuthData.oAuthToken);
151 session.setSteamID(oAuthData.steamID);
152 session.setSteamLogin(session.getSteamID() + "%7C%7C" + oAuthData.steamLogin);
153 session.setSteamLoginSecure(session.getSteamID() + "%7C%7C" + oAuthData.steamLoginSecure);
154 session.setWebCookie(oAuthData.webCookie);
155
156 Cookie httpCookie = cookies
157 .getCookies()
158 .stream()
159 .filter(cookie -> cookie.getName().equals("sessionId"))
160 .findFirst().orElse(null);
161
162 session.setSessionID(httpCookie.getValue());
163
164 this.session = session;
165 loggedIn = true;
166 return LoginResult.LoginOkay;
167 }
168
169 }
170
171 private String encryptPassword(RSAResponse rsaResponse) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
172 byte[] passwordBytes = password.getBytes(StandardCharsets.US_ASCII);
173 BigInteger modulus = new BigInteger(1, hexStringToByteArray(rsaResponse.modulus));
174 BigInteger publicExponent = new BigInteger(1, hexStringToByteArray(rsaResponse.exponent));
175
176 Cipher cipher;
177 //RSA config
178
179 RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, publicExponent);
180 KeyFactory fact = KeyFactory.getInstance("RSA");
181 PublicKey pubKey = fact.generatePublic(rsaPubKey);
182 cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
183 cipher.init(Cipher.ENCRYPT_MODE, pubKey);
184 byte[] cipherData = cipher.doFinal(passwordBytes);
185 return Base64.encodeBase64String(cipherData);
186 }
187
188 private byte[] hexStringToByteArray(String s) {
189 int len = s.length();
190 byte[] data = new byte[len / 2];
191 for (int i = 0; i < len; i += 2) {
192 data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
193 + Character.digit(s.charAt(i + 1), 16));
194 }
195 return data;
196 }
197
198 private BasicClientCookie createCookie(String name, String value, String path, String domain) {
199 BasicClientCookie cookie = new BasicClientCookie(name, value);
200 cookie.setPath(path);
201 cookie.setDomain(domain);
202 return cookie;
203 }
204
205 public enum LoginResult {
206 LoginOkay,
207 GeneralFailure,
208 BadRSA,
209 BadCredentials,
210 NeedCaptcha,
211 Need2FA,
212 NeedEmail,
213 TooManyFailedLogins
214 }
215
216 static class RSAResponse {
217 public boolean success;
218 public String exponent;
219 public String modulus;
220 public String timestamp;
221 public String steamID;
222
223 private RSAResponse() {
224 }
225
226 public static RSAResponse parseRSA(String rsa) {
227 RSAResponse rsaResponse = new RSAResponse();
228 JSONParser jsonParser = new JSONParser();
229 JSONObject jsonObject = null;
230 try {
231 jsonObject = (JSONObject) jsonParser.parse(rsa);
232 } catch (ParseException e) {
233 e.printStackTrace();
234 }
235 if (jsonObject == null) {
236 return null;
237 }
238 rsaResponse.success = (Boolean) jsonObject.get("success");
239 rsaResponse.exponent = (String) jsonObject.get("publickey_exp");
240 rsaResponse.modulus = (String) jsonObject.get("publickey_mod");
241 rsaResponse.timestamp = (String) jsonObject.get("timestamp");
242 rsaResponse.steamID = (String) jsonObject.get("token_gid"); //TODO can be mistake
243 return rsaResponse;
244 }
245 }
246
247 static class LoginResponse {
248 public boolean success;
249 public boolean loginComplete;
250 private String oAuthDataString;
251 public boolean captchaNeeded;
252 public String captchaGID;
253 public long emailSteamID;
254 public boolean emailAuthNeeded;
255 public boolean twoFactorNeeded;
256 public String message;
257
258 private LoginResponse() {
259
260 }
261
262 public static LoginResponse parseLoginResponse(String loginResponseStr) {
263 LoginResponse loginResponse = new LoginResponse();
264 JSONParser jsonParser = new JSONParser();
265 JSONObject jsonObject = null;
266 try {
267 jsonObject = (JSONObject) jsonParser.parse(loginResponseStr);
268 } catch (ParseException e) {
269 e.printStackTrace();
270 }
271 if (jsonObject == null) {
272 return null;
273 }
274
275 loginResponse.success = (Boolean) jsonObject.get("success");
276 if (jsonObject.get("login_complete") != null) {
277 loginResponse.loginComplete = (Boolean) jsonObject.get("login_complete");
278 }
279 loginResponse.oAuthDataString = (String) jsonObject.get("oauth");
280 if (jsonObject.get("captcha_needed") != null) {
281 loginResponse.captchaNeeded = (Boolean) jsonObject.get("captcha_needed");
282 }
283 loginResponse.captchaGID = jsonObject.get("captcha_gid").toString();
284 if (jsonObject.get("emailsteamid") != null) {
285 loginResponse.emailSteamID = Long.parseLong((String) jsonObject.get("emailsteamid"));
286 }
287 if (jsonObject.get("emailauth_needed") != null) {
288 loginResponse.emailAuthNeeded = (Boolean) jsonObject.get("emailauth_needed");
289 }
290 loginResponse.twoFactorNeeded = (Boolean) jsonObject.get("requires_twofactor");
291 loginResponse.message = (String) jsonObject.get("message");
292 return loginResponse;
293 }
294
295 public OAuth getOAuthData() {
296 return oAuthDataString != null ? OAuth.parseOAuth(oAuthDataString) : null;
297 }
298 }
299
300 static class OAuth {
301 public long steamID;
302 public String oAuthToken;
303 public String steamLogin;
304 public String steamLoginSecure;
305 public String webCookie;
306
307 private OAuth() {
308
309 }
310
311 public static OAuth parseOAuth(String oAuthStr) {
312 OAuth oAuth = new OAuth();
313 JSONParser jsonParser = new JSONParser();
314 JSONObject jsonObject = null;
315 try {
316 jsonObject = (JSONObject) jsonParser.parse(oAuthStr);
317 } catch (ParseException e) {
318 e.printStackTrace();
319 }
320 if (jsonObject == null) {
321 return null;
322 }
323
324 oAuth.steamID = Long.parseLong(jsonObject.get("steamid").toString());
325 oAuth.oAuthToken = (String) jsonObject.get("oauth_token");
326 oAuth.steamLogin = (String) jsonObject.get("wgtoken");
327 oAuth.steamLogin = (String) jsonObject.get("wgtoken");
328 oAuth.steamLoginSecure = (String) jsonObject.get("wgtoken_secure");
329 oAuth.webCookie = (String) jsonObject.get("webcookie");
330 return oAuth;
331 }
332 }
333
334 public String getUserName() {
335 return userName;
336 }
337
338 public void setUserName(String userName) {
339 this.userName = userName;
340 }
341
342 public String getPassword() {
343 return password;
344 }
345
346 public void setPassword(String password) {
347 this.password = password;
348 }
349
350 public long getSteamID() {
351 return steamID;
352 }
353
354 public void setSteamID(long steamID) {
355 this.steamID = steamID;
356 }
357
358 public boolean isRequiresCaptcha() {
359 return requiresCaptcha;
360 }
361
362 public void setRequiresCaptcha(boolean requiresCaptcha) {
363 this.requiresCaptcha = requiresCaptcha;
364 }
365
366 public String getCaptchaGID() {
367 return captchaGID;
368 }
369
370 public void setCaptchaGID(String captchaGID) {
371 this.captchaGID = captchaGID;
372 }
373
374 public String getCaptchaText() {
375 return captchaText;
376 }
377
378 public void setCaptchaText(String captchaText) {
379 this.captchaText = captchaText;
380 }
381
382 public boolean isRequiresEmail() {
383 return requiresEmail;
384 }
385
386 public void setRequiresEmail(boolean requiresEmail) {
387 this.requiresEmail = requiresEmail;
388 }
389
390 public String getEmailDomain() {
391 return emailDomain;
392 }
393
394 public void setEmailDomain(String emailDomain) {
395 this.emailDomain = emailDomain;
396 }
397
398 public String getEmailCode() {
399 return emailCode;
400 }
401
402 public void setEmailCode(String emailCode) {
403 this.emailCode = emailCode;
404 }
405
406 public boolean isRequires2FA() {
407 return requires2FA;
408 }
409
410 public void setRequires2FA(boolean requires2FA) {
411 this.requires2FA = requires2FA;
412 }
413
414 public String getTwoFactorCode() {
415 return twoFactorCode;
416 }
417
418 public void setTwoFactorCode(String twoFactorCode) {
419 this.twoFactorCode = twoFactorCode;
420 }
421
422 public SessionData getSession() {
423 return session;
424 }
425
426 public void setSession(SessionData session) {
427 this.session = session;
428 }
429
430 public boolean isLoggedIn() {
431 return loggedIn;
432 }
433
434 public void setLoggedIn(boolean loggedIn) {
435 this.loggedIn = loggedIn;
436 }
437
438 public CookieStore getCookies() {
439 return cookies;
440 }
441
442 public void setCookies(CookieStore cookies) {
443 this.cookies = cookies;
444 }
445}