<commit_before>package org.to2mbn.jmccc.auth.yggdrasil;

import java.io.Serializable;
import java.util.Objects;
import java.util.UUID;
import org.json.JSONObject;
import org.to2mbn.jmccc.auth.AuthInfo;
import org.to2mbn.jmccc.auth.Authenticator;
import org.to2mbn.jmccc.auth.yggdrasil.core.Agent;
import org.to2mbn.jmccc.auth.yggdrasil.core.GameProfile;
import org.to2mbn.jmccc.auth.yggdrasil.core.Session;
import org.to2mbn.jmccc.auth.yggdrasil.core.AuthenticationService;
import org.to2mbn.jmccc.auth.yggdrasil.core.util.UUIDUtils;
import org.to2mbn.jmccc.auth.yggdrasil.core.yggdrasil.YggdrasilAuthenticationService;
import org.to2mbn.jmccc.auth.AuthenticationException;

public class YggdrasilAuthenticator implements Authenticator, Serializable {

	public static interface PasswordProvider {

		String getUsername() throws AuthenticationException;

		String getPassword() throws AuthenticationException;

		CharacterSelector getCharacterSelector();

	}
	
	public static YggdrasilAuthenticator token(String accessToken, String clientToken) throws AuthenticationException {
		return token(accessToken, new YggdrasilAuthenticationService(clientToken, Agent.MINECRAFT));
	}

	public static YggdrasilAuthenticator token(String accessToken, AuthenticationService service) throws AuthenticationException {
		YggdrasilAuthenticator auth = new YggdrasilAuthenticator(service);
		auth.refreshWithToken(accessToken);
		return auth;
	}

	public static YggdrasilAuthenticator password(String username, String password) throws AuthenticationException {
		return password(username, password, null);
	}
	
	public static YggdrasilAuthenticator password(String username, String password, CharacterSelector characterSelector) throws AuthenticationException {
		return password(username, password, characterSelector, UUIDUtils.unsign(UUID.randomUUID()));
	}

	public static YggdrasilAuthenticator password(String username, String password, CharacterSelector characterSelector, String clientToken) throws AuthenticationException {
		return password(username, password, characterSelector, new YggdrasilAuthenticationService(clientToken, Agent.MINECRAFT));
	}

	public static YggdrasilAuthenticator password(final String username, final String password, final CharacterSelector characterSelector, AuthenticationService service) throws AuthenticationException {
		YggdrasilAuthenticator auth = new YggdrasilAuthenticator(service);
		auth.refreshWithPassword(new PasswordProvider() {

			@Override
			public String getUsername() throws AuthenticationException {
				return username;
			}

			@Override
			public String getPassword() throws AuthenticationException {
				return password;
			}

			@Override
			public CharacterSelector getCharacterSelector() {
				return characterSelector;
			}
		});
		return auth;
	}

	private static final long serialVersionUID = 1L;

	private AuthenticationService sessionService;
	private volatile Session authResult;

	public YggdrasilAuthenticator() {
		this(UUIDUtils.unsign(UUID.randomUUID()));
	}

	public YggdrasilAuthenticator(String clientToken) {
		this(new YggdrasilAuthenticationService(clientToken, Agent.MINECRAFT));
	}

	public YggdrasilAuthenticator(AuthenticationService sessionService) {
		Objects.requireNonNull(sessionService);
		this.sessionService = sessionService;
	}

	@Override
	public synchronized AuthInfo auth() throws AuthenticationException {
		GameProfile selectedProfile = session().getSelectedProfile();
		if (selectedProfile == null) {
			throw new AuthenticationException("no profile is available");
		}
		return new AuthInfo(selectedProfile.getName(), authResult.getAccessToken(), UUIDUtils.unsign(selectedProfile.getUUID()), authResult.getProperties(), authResult.getUserType().getName());
	}

	public synchronized Session session() throws AuthenticationException {
		if (authResult == null || !sessionService.validate(authResult.getAccessToken())) {
			refresh();
		}
		if (authResult == null) {
			throw new AuthenticationException("no authentication is available");
		}
		return authResult;
	}

	public synchronized void refresh() throws AuthenticationException {
		if (authResult == null) {
			// refresh operation is not available
			PasswordProvider passwordProvider = tryPasswordLogin();
			if (passwordProvider == null) {
				throw new AuthenticationException("no more authentication methods to try");
			}
			refreshWithPassword(passwordProvider);
		} else {
			try {
				refreshWithToken(authResult.getAccessToken());
			} catch (AuthenticationException e) {
				// token login failed
				PasswordProvider passwordProvider = tryPasswordLogin();
				if (passwordProvider == null) {
					throw e;
				}

				try {
					refreshWithPassword(passwordProvider);
				} catch (AuthenticationException e1) {
					e1.addSuppressed(e);
					throw e1;
				}
			}
		}
	}

	public synchronized void refreshWithPassword(PasswordProvider passwordProvider) throws AuthenticationException {
		Objects.requireNonNull(passwordProvider);
		authResult = sessionService.login(passwordProvider.getUsername(), passwordProvider.getPassword());
		if (authResult.getSelectedProfile() == null) {
			// no profile is selected
			// let's select one
			CharacterSelector selector = passwordProvider.getCharacterSelector();
			if (selector == null) {
				selector = new DefaultCharacterSelector();
			}
			GameProfile[] profiles = authResult.getProfiles();
			if (profiles == null || profiles.length == 0) {
				throw new AuthenticationException("no profile is available");
			}
			GameProfile selectedProfile = selector.select(profiles);
			authResult = sessionService.selectProfile(authResult.getAccessToken(), selectedProfile.getUUID());
		}
	}

	public synchronized void refreshWithToken(String accessToken) throws AuthenticationException {
		Objects.requireNonNull(accessToken);
		authResult = sessionService.refresh(accessToken);
	}

	public synchronized void clearToken() {
		authResult = null;
	}

	public synchronized Session getCurrentSession() {
		return authResult;
	}

	public synchronized void setCurrentSession(Session session) {
		this.authResult = session;
	}

	protected PasswordProvider tryPasswordLogin() throws AuthenticationException {<commit_msg>add getAuthenticationService() for YggdrasilAuthenticator<commit_after>package org.to2mbn.jmccc.auth.yggdrasil;

import java.io.Serializable;
import java.util.Objects;
import java.util.UUID;
import org.to2mbn.jmccc.auth.AuthInfo;
import org.to2mbn.jmccc.auth.AuthenticationException;
import org.to2mbn.jmccc.auth.Authenticator;
import org.to2mbn.jmccc.auth.yggdrasil.core.Agent;
import org.to2mbn.jmccc.auth.yggdrasil.core.AuthenticationService;
import org.to2mbn.jmccc.auth.yggdrasil.core.GameProfile;
import org.to2mbn.jmccc.auth.yggdrasil.core.Session;
import org.to2mbn.jmccc.auth.yggdrasil.core.util.UUIDUtils;
import org.to2mbn.jmccc.auth.yggdrasil.core.yggdrasil.YggdrasilAuthenticationService;

public class YggdrasilAuthenticator implements Authenticator, Serializable {

	public static interface PasswordProvider {

		String getUsername() throws AuthenticationException;

		String getPassword() throws AuthenticationException;

		CharacterSelector getCharacterSelector();

	}
	
	public static YggdrasilAuthenticator token(String accessToken, String clientToken) throws AuthenticationException {
		return token(accessToken, new YggdrasilAuthenticationService(clientToken, Agent.MINECRAFT));
	}

	public static YggdrasilAuthenticator token(String accessToken, AuthenticationService service) throws AuthenticationException {
		YggdrasilAuthenticator auth = new YggdrasilAuthenticator(service);
		auth.refreshWithToken(accessToken);
		return auth;
	}

	public static YggdrasilAuthenticator password(String username, String password) throws AuthenticationException {
		return password(username, password, null);
	}
	
	public static YggdrasilAuthenticator password(String username, String password, CharacterSelector characterSelector) throws AuthenticationException {
		return password(username, password, characterSelector, UUIDUtils.unsign(UUID.randomUUID()));
	}

	public static YggdrasilAuthenticator password(String username, String password, CharacterSelector characterSelector, String clientToken) throws AuthenticationException {
		return password(username, password, characterSelector, new YggdrasilAuthenticationService(clientToken, Agent.MINECRAFT));
	}

	public static YggdrasilAuthenticator password(final String username, final String password, final CharacterSelector characterSelector, AuthenticationService service) throws AuthenticationException {
		YggdrasilAuthenticator auth = new YggdrasilAuthenticator(service);
		auth.refreshWithPassword(new PasswordProvider() {

			@Override
			public String getUsername() throws AuthenticationException {
				return username;
			}

			@Override
			public String getPassword() throws AuthenticationException {
				return password;
			}

			@Override
			public CharacterSelector getCharacterSelector() {
				return characterSelector;
			}
		});
		return auth;
	}

	private static final long serialVersionUID = 1L;

	private AuthenticationService authenticationService;
	private volatile Session authResult;

	public YggdrasilAuthenticator() {
		this(UUIDUtils.unsign(UUID.randomUUID()));
	}

	public YggdrasilAuthenticator(String clientToken) {
		this(new YggdrasilAuthenticationService(clientToken, Agent.MINECRAFT));
	}

	public YggdrasilAuthenticator(AuthenticationService sessionService) {
		Objects.requireNonNull(sessionService);
		this.authenticationService = sessionService;
	}

	@Override
	public synchronized AuthInfo auth() throws AuthenticationException {
		GameProfile selectedProfile = session().getSelectedProfile();
		if (selectedProfile == null) {
			throw new AuthenticationException("no profile is available");
		}
		return new AuthInfo(selectedProfile.getName(), authResult.getAccessToken(), UUIDUtils.unsign(selectedProfile.getUUID()), authResult.getProperties(), authResult.getUserType().getName());
	}

	public synchronized Session session() throws AuthenticationException {
		if (authResult == null || !authenticationService.validate(authResult.getAccessToken())) {
			refresh();
		}
		if (authResult == null) {
			throw new AuthenticationException("no authentication is available");
		}
		return authResult;
	}

	public synchronized void refresh() throws AuthenticationException {
		if (authResult == null) {
			// refresh operation is not available
			PasswordProvider passwordProvider = tryPasswordLogin();
			if (passwordProvider == null) {
				throw new AuthenticationException("no more authentication methods to try");
			}
			refreshWithPassword(passwordProvider);
		} else {
			try {
				refreshWithToken(authResult.getAccessToken());
			} catch (AuthenticationException e) {
				// token login failed
				PasswordProvider passwordProvider = tryPasswordLogin();
				if (passwordProvider == null) {
					throw e;
				}

				try {
					refreshWithPassword(passwordProvider);
				} catch (AuthenticationException e1) {
					e1.addSuppressed(e);
					throw e1;
				}
			}
		}
	}

	public synchronized void refreshWithPassword(PasswordProvider passwordProvider) throws AuthenticationException {
		Objects.requireNonNull(passwordProvider);
		authResult = authenticationService.login(passwordProvider.getUsername(), passwordProvider.getPassword());
		if (authResult.getSelectedProfile() == null) {
			// no profile is selected
			// let's select one
			CharacterSelector selector = passwordProvider.getCharacterSelector();
			if (selector == null) {
				selector = new DefaultCharacterSelector();
			}
			GameProfile[] profiles = authResult.getProfiles();
			if (profiles == null || profiles.length == 0) {
				throw new AuthenticationException("no profile is available");
			}
			GameProfile selectedProfile = selector.select(profiles);
			authResult = authenticationService.selectProfile(authResult.getAccessToken(), selectedProfile.getUUID());
		}
	}

	public synchronized void refreshWithToken(String accessToken) throws AuthenticationException {
		Objects.requireNonNull(accessToken);
		authResult = authenticationService.refresh(accessToken);
	}

	public synchronized void clearToken() {
		authResult = null;
	}

	public synchronized Session getCurrentSession() {
		return authResult;
	}

	public synchronized void setCurrentSession(Session session) {
		this.authResult = session;
	}

	public AuthenticationService getAuthenticationService() {
		return authenticationService;
	}

	protected PasswordProvider tryPasswordLogin() throws AuthenticationException {
{'fraction_non_alphanumeric': 0.0831673703497172, 'fraction_numerical': 0.0023898669640723333, 'mean_word_length': 5.793290043290043, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '265214', 'n_tokens_mistral': 3735, 'n_tokens_neox': 3322, 'n_words': 780}