New login UI (#29)

* Refactor activity names
* Refactor login activity and async task
* Add forgot password and create account links
* Login without passing symbol in login form
* Add heading text before login form
* Refactor API/login
* Add login loading steps
* Remove unnecessary try catch
* Refactor snp and add tests
* Remove redudant throws clauses
This commit is contained in:
Mikołaj Pich 2017-10-27 17:48:17 +02:00 committed by GitHub
parent f6e29490c3
commit d796702ade
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 1221 additions and 506 deletions

View File

@ -39,7 +39,7 @@ android {
}
greendao {
schemaVersion 13
schemaVersion 14
generateTests = true
}
@ -57,6 +57,7 @@ dependencies {
compile 'org.apache.commons:commons-collections4:4.1'
compile 'org.jsoup:jsoup:1.10.3'
compile 'org.greenrobot:greendao:3.2.2'
compile 'com.android.support:customtabs:27.0.0'
debugCompile 'com.amitshekhar.android:debug-db:1.0.1'
debugCompile 'net.zetetic:android-database-sqlcipher:3.5.7@aar'

View File

@ -20,8 +20,6 @@ import io.github.wulkanowy.api.Vulcan;
import io.github.wulkanowy.api.login.AccountPermissionException;
import io.github.wulkanowy.api.login.BadCredentialsException;
import io.github.wulkanowy.api.login.LoginErrorException;
import io.github.wulkanowy.api.user.BasicInformation;
import io.github.wulkanowy.api.user.PersonalData;
import io.github.wulkanowy.dao.entities.Account;
import io.github.wulkanowy.dao.entities.AccountDao;
import io.github.wulkanowy.dao.entities.DaoMaster;
@ -29,10 +27,10 @@ import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.security.Safety;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.synchronisation.AccountSynchronisation;
import io.github.wulkanowy.services.synchronisation.AccountAuthorization;
@RunWith(AndroidJUnit4.class)
public class AccountSynchronizationTest {
public class AccountAuthorizationTest {
private static DaoSession daoSession;
@ -64,8 +62,8 @@ public class AccountSynchronizationTest {
public void emptyUserIdTest() throws CryptoException, BadCredentialsException,
AccountPermissionException, IOException, LoginErrorException {
AccountSynchronisation accountSynchronisation = new AccountSynchronisation();
accountSynchronisation.loginCurrentUser(context, daoSession, new Vulcan());
AccountAuthorization accountAuthorization = new AccountAuthorization(context, daoSession, new Vulcan());
accountAuthorization.loginCurrentUser();
}
@Test
@ -82,10 +80,10 @@ public class AccountSynchronizationTest {
setUserIdSharePreferences(userId);
Vulcan vulcan = Mockito.mock(Vulcan.class);
Mockito.doNothing().when(vulcan).login("TEST@TEST", "TEST", "");
Mockito.doNothing().when(vulcan).login("TEST@TEST", "TEST", "TEST_SYMBOL", "TEST_ID");
AccountSynchronisation accountSynchronisation = new AccountSynchronisation();
LoginSession loginSession = accountSynchronisation.loginCurrentUser(targetContext, daoSession, vulcan);
AccountAuthorization accountAuthorization = new AccountAuthorization(targetContext, daoSession, vulcan);
LoginSession loginSession = accountAuthorization.loginCurrentUser();
Assert.assertNotNull(loginSession);
Assert.assertEquals(loginSession.getUserId(), userId);
@ -93,50 +91,16 @@ public class AccountSynchronizationTest {
Assert.assertEquals(loginSession.getVulcan(), vulcan);
}
@Test
public void loginNewUserTest() throws Exception {
PersonalData personalData = Mockito.mock(PersonalData.class);
Mockito.doReturn("NAME-TEST").when(personalData).getFirstAndLastName();
BasicInformation basicInformation = Mockito.mock(BasicInformation.class);
Mockito.doReturn(personalData).when(basicInformation).getPersonalData();
Vulcan vulcan = Mockito.mock(Vulcan.class);
Mockito.doNothing().when(vulcan).login("TEST@TEST", "TEST", "");
Mockito.doReturn(basicInformation).when(vulcan).getBasicInformation();
AccountSynchronisation accountSynchronisation = new AccountSynchronisation();
LoginSession loginSession = accountSynchronisation
.loginNewUser("TEST@TEST", "TEST", "", targetContext, daoSession, vulcan);
Long userId = targetContext.getSharedPreferences("LoginData", Context.MODE_PRIVATE).getLong("userId", 0);
Assert.assertNotNull(loginSession);
Assert.assertNotEquals(0, userId.longValue());
Assert.assertEquals(loginSession.getUserId(), userId);
Assert.assertNotNull(loginSession.getDaoSession());
Assert.assertEquals(loginSession.getVulcan(), vulcan);
Safety safety = new Safety();
Account account = daoSession.getAccountDao().load(userId);
Assert.assertNotNull(account);
Assert.assertEquals("TEST@TEST", account.getEmail());
Assert.assertEquals("NAME-TEST", account.getName());
Assert.assertEquals("TEST", safety.decrypt("TEST@TEST", account.getPassword()));
}
@AfterClass
public static void cleanUp() {
daoSession.getAccountDao().deleteAll();
daoSession.clear();
}
private void setUserIdSharePreferences(long id) {
SharedPreferences sharedPreferences = targetContext.getSharedPreferences("LoginData", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putLong("userId", id);
editor.apply();
}
@AfterClass
public static void cleanUp() {
daoSession.getAccountDao().deleteAll();
daoSession.clear();
}
}

View File

@ -0,0 +1,115 @@
package io.github.wulkanowy.services.synchronization;
import android.content.Context;
import android.content.SharedPreferences;
import android.support.test.InstrumentationRegistry;
import org.greenrobot.greendao.database.Database;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
import io.github.wulkanowy.api.StudentAndParent;
import io.github.wulkanowy.api.Vulcan;
import io.github.wulkanowy.api.login.Login;
import io.github.wulkanowy.api.user.BasicInformation;
import io.github.wulkanowy.api.user.PersonalData;
import io.github.wulkanowy.dao.entities.Account;
import io.github.wulkanowy.dao.entities.DaoMaster;
import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.security.Safety;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.synchronisation.AccountRegistration;
public class AccountRegistrationTest {
private static DaoSession daoSession;
private Context targetContext;
@BeforeClass
public static void setUpClass() {
DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(InstrumentationRegistry.getTargetContext(), "wulkanowyTest-database");
Database database = devOpenHelper.getWritableDb();
daoSession = new DaoMaster(database).newSession();
}
@Before
public void setUp() {
targetContext = InstrumentationRegistry.getTargetContext();
daoSession.getAccountDao().deleteAll();
daoSession.clear();
setUserIdSharePreferences(0);
}
@Test
public void connectTest() throws Exception {
String certificate = "<xml>Certificate</xml>";
Login login = Mockito.mock(Login.class);
Mockito.when(login.sendCredentials(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()))
.thenReturn(certificate);
AccountRegistration accountRegistration = new AccountRegistration(login, new Vulcan(), "TEST@TEST", "TEST_PASS", "TEST_SYMBOL");
Assert.assertEquals(certificate, accountRegistration.connect());
}
@Test
public void loginTest() throws Exception {
StudentAndParent snp = Mockito.mock(StudentAndParent.class);
Mockito.when(snp.getSymbol()).thenReturn("TEST-SYMBOL");
Mockito.when(snp.getId()).thenReturn("TEST-ID");
PersonalData personalData = Mockito.mock(PersonalData.class);
Mockito.doReturn("NAME-TEST").when(personalData).getFirstAndLastName();
BasicInformation basicInformation = Mockito.mock(BasicInformation.class);
Mockito.doReturn(personalData).when(basicInformation).getPersonalData();
Vulcan vulcan = Mockito.mock(Vulcan.class);
Mockito.doReturn(basicInformation).when(vulcan).getBasicInformation();
Mockito.doReturn(snp).when(vulcan).getStudentAndParent();
Login login = Mockito.mock(Login.class);
Mockito.when(login.sendCertificate(Mockito.anyString(), Mockito.anyString())).thenReturn("TEST-SYMBOL");
AccountRegistration accountRegistration = new AccountRegistration(login, vulcan, "TEST@TEST", "TEST-PASS", "default");
LoginSession loginSession = accountRegistration.login(targetContext, daoSession, "<xml>cert</xml>");
Long userId = targetContext.getSharedPreferences("LoginData", Context.MODE_PRIVATE).getLong("userId", 0);
Assert.assertNotNull(loginSession);
Assert.assertNotEquals(0, userId.longValue());
Assert.assertEquals(loginSession.getUserId(), userId);
Assert.assertNotNull(loginSession.getDaoSession());
Assert.assertEquals(loginSession.getVulcan(), vulcan);
Safety safety = new Safety();
Account account = daoSession.getAccountDao().load(userId);
Assert.assertNotNull(account);
Assert.assertEquals("TEST@TEST", account.getEmail());
Assert.assertEquals("NAME-TEST", account.getName());
Assert.assertEquals("TEST-PASS", safety.decrypt("TEST@TEST", account.getPassword()));
Assert.assertEquals("TEST-SYMBOL", account.getSymbol());
Assert.assertEquals("TEST-ID", account.getSnpId());
}
private void setUserIdSharePreferences(long id) {
SharedPreferences sharedPreferences = targetContext.getSharedPreferences("LoginData", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putLong("userId", id);
editor.apply();
}
@AfterClass
public static void cleanUp() {
daoSession.getAccountDao().deleteAll();
daoSession.clear();
}
}

View File

@ -19,7 +19,7 @@
android:supportsRtl="true"
android:theme="@style/WulkanowyTheme">
<activity
android:name=".activity.started.StartedActivity"
android:name=".activity.splash.SplashActivity"
android:configChanges="orientation|screenSize"
android:noHistory="true"
android:theme="@style/WulkanowyTheme.noActionBar">
@ -30,9 +30,9 @@
</intent-filter>
</activity>
<activity
android:name=".activity.main.MainActivity"
android:name=".activity.login.LoginActivity"
android:configChanges="orientation|screenSize"
android:label="@string/login_text"
android:label="@string/title_activity_login"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".activity.dashboard.DashboardActivity"

View File

@ -0,0 +1,210 @@
package io.github.wulkanowy.activity.login;
import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.customtabs.CustomTabsIntent;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.util.LinkedHashMap;
import io.github.wulkanowy.R;
/**
* A login screen that offers login via email/password.
*/
public class LoginActivity extends Activity {
private float touchPosition;
private EditText emailView;
private EditText passwordView;
private AutoCompleteTextView symbolView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// Set up the login form.
emailView = findViewById(R.id.email);
passwordView = findViewById(R.id.password);
symbolView = findViewById(R.id.symbol);
passwordView.setOnEditorActionListener(getTextViewSignInListener());
symbolView.setOnEditorActionListener(getTextViewSignInListener());
populateAutoComplete();
Button signInButton = findViewById(R.id.action_sign_in);
signInButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
attemptLogin();
}
});
findViewById(R.id.action_create_account).setOnClickListener(getButtonLinkListener(
"https://cufs.vulcan.net.pl/Default/AccountManage/CreateAccount"
));
findViewById(R.id.action_forgot_password).setOnClickListener(getButtonLinkListener(
"https://cufs.vulcan.net.pl/Default/AccountManage/UnlockAccount"
));
}
private TextView.OnEditorActionListener getTextViewSignInListener() {
return new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) {
attemptLogin();
return true;
}
return false;
}
};
}
private OnClickListener getButtonLinkListener(final String url) {
return new OnClickListener() {
@Override
public void onClick(View view) {
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
builder.setToolbarColor(getResources().getColor(R.color.colorPrimary));
customTabsIntent.launchUrl(view.getContext(), Uri.parse(url));
}
};
}
private void populateAutoComplete() {
// Get the string array
String[] countries = getResources().getStringArray(R.array.symbols);
// Create the adapter and set it to the AutoCompleteTextView
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
countries);
symbolView.setAdapter(adapter);
}
/**
* Attempts to sign in the account specified by the login form.
*/
private void attemptLogin() {
// Reset errors.
emailView.setError(null);
passwordView.setError(null);
// Store values at the time of the login attempt.
String email = emailView.getText().toString();
String password = passwordView.getText().toString();
String symbol = symbolView.getText().toString();
boolean cancel = false;
View focusView = null;
// Check for a valid password.
if (TextUtils.isEmpty(password)) {
passwordView.setError(getString(R.string.error_field_required));
focusView = passwordView;
cancel = true;
} else if (!isPasswordValid(password)) {
passwordView.setError(getString(R.string.error_invalid_password));
focusView = passwordView;
cancel = true;
}
// Check for a valid email address.
if (TextUtils.isEmpty(email)) {
emailView.setError(getString(R.string.error_field_required));
focusView = emailView;
cancel = true;
} else if (!isEmailValid(email)) {
emailView.setError(getString(R.string.error_invalid_email));
focusView = emailView;
cancel = true;
}
// Check for a valid symbol.
if (TextUtils.isEmpty(symbol)) {
symbol = "Default";
}
String[] keys = this.getResources().getStringArray(R.array.symbols);
String[] values = this.getResources().getStringArray(R.array.symbols_values);
LinkedHashMap<String, String> map = new LinkedHashMap<>();
for (int i = 0; i < Math.min(keys.length, values.length); ++i) {
map.put(keys[i], values[i]);
}
if (map.containsKey(symbol)) {
symbol = map.get(symbol);
}
if (cancel) {
// There was an error; don't attempt login and focus the first
// form field with an error.
focusView.requestFocus();
} else {
// Show a progress spinner, and kick off a background task to
// perform the user login attempt.
LoginTask authTask = new LoginTask(this, email, password, symbol);
authTask.showProgress(true);
authTask.execute();
}
}
private boolean isEmailValid(String email) {
return email.contains("@");
}
private boolean isPasswordValid(String password) {
return password.length() > 7;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
touchPosition = ev.getY();
}
if (ev.getAction() == MotionEvent.ACTION_UP) {
float releasePosition = ev.getY();
if (touchPosition - releasePosition == 0) {
View view = getCurrentFocus();
if (view != null && (ev.getAction() == MotionEvent.ACTION_UP
|| ev.getAction() == MotionEvent.ACTION_MOVE) && view instanceof EditText
&& !view.getClass().getName().startsWith("android.webkit.")) {
int scrcoords[] = new int[2];
view.getLocationOnScreen(scrcoords);
float x = ev.getRawX() + view.getLeft() - scrcoords[0];
float y = ev.getRawY() + view.getTop() - scrcoords[1];
if (x < view.getLeft() || x > view.getRight() || y < view.getTop()
|| y > view.getBottom()) {
((InputMethodManager) this.getSystemService(
Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(
(this.getWindow().getDecorView().getApplicationWindowToken()), 0);
}
}
}
}
return super.dispatchTouchEvent(ev);
}
}

View File

@ -0,0 +1,186 @@
package io.github.wulkanowy.activity.login;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TextInputLayout;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import java.io.IOException;
import io.github.wulkanowy.R;
import io.github.wulkanowy.activity.WulkanowyApp;
import io.github.wulkanowy.activity.dashboard.DashboardActivity;
import io.github.wulkanowy.api.Cookies;
import io.github.wulkanowy.api.Vulcan;
import io.github.wulkanowy.api.login.AccountPermissionException;
import io.github.wulkanowy.api.login.BadCredentialsException;
import io.github.wulkanowy.api.login.Login;
import io.github.wulkanowy.api.login.NotLoggedInErrorException;
import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.VulcanSynchronization;
import io.github.wulkanowy.services.synchronisation.AccountRegistration;
import io.github.wulkanowy.utilities.ConnectionUtilities;
/**
* Represents an asynchronous login/registration task used to authenticate
* the user.
*/
public class LoginTask extends AsyncTask<Void, String, Integer> {
private final String email;
private final String password;
private final String symbol;
private Activity activity;
private View progressView;
private View loginFormView;
private TextView showText;
public LoginTask(Activity activity, String email, String password, String symbol) {
this.activity = activity;
this.email = email;
this.password = password;
this.symbol = symbol;
}
@Override
protected void onPreExecute() {
showText = activity.findViewById(R.id.login_progress_text);
}
@Override
protected Integer doInBackground(Void... params) {
if (ConnectionUtilities.isOnline(activity)) {
AccountRegistration accountRegistration = new AccountRegistration(
new Login(new Cookies()),
new Vulcan(),
email, password, symbol);
DaoSession daoSession = ((WulkanowyApp) activity.getApplication()).getDaoSession();
try {
publishProgress("1", activity.getResources().getString(R.string.step_connecting));
String certificate = accountRegistration.connect();
publishProgress("2", activity.getResources().getString(R.string.step_login));
LoginSession loginSession = accountRegistration.login(activity, daoSession, certificate);
publishProgress("3", activity.getResources().getString(R.string.step_synchronization));
VulcanSynchronization vulcanSynchronization = new VulcanSynchronization(loginSession);
vulcanSynchronization.syncSubjectsAndGrades();
} catch (BadCredentialsException e) {
return R.string.login_bad_credentials_text;
} catch (AccountPermissionException e) {
return R.string.error_bad_account_permission;
} catch (CryptoException e) {
return R.string.encrypt_failed_text;
} catch (NotLoggedInErrorException | IOException e) {
return R.string.login_denied_text;
}
accountRegistration.scheduleSynchronization(activity);
return R.string.login_accepted_text;
} else {
return R.string.noInternet_text;
}
}
@Override
protected void onProgressUpdate(String... progress) {
showText.setText(progress[0] + "/3 - " + progress[1] + "...");
}
@Override
protected void onPostExecute(final Integer messageID) {
showProgress(false);
switch (messageID) {
// if success
case R.string.login_accepted_text:
Intent intent = new Intent(activity, DashboardActivity.class);
activity.finish();
activity.startActivity(intent);
break;
// if bad credentials entered
case R.string.login_bad_credentials_text:
EditText passwordView = activity.findViewById(R.id.password);
passwordView.setError(activity.getString(R.string.error_incorrect_password));
passwordView.requestFocus();
break;
// if no permission
case R.string.error_bad_account_permission:
// Change to visible symbol input view
TextInputLayout symbolLayout = activity.findViewById(R.id.to_symbol_input_layout);
symbolLayout.setVisibility(View.VISIBLE);
EditText symbolView = activity.findViewById(R.id.symbol);
symbolView.setError(activity.getString(R.string.error_bad_account_permission));
symbolView.requestFocus();
break;
default:
Snackbar
.make(activity.findViewById(R.id.coordinatorLayout), messageID, Snackbar.LENGTH_LONG)
.show();
break;
}
}
@Override
protected void onCancelled() {
showProgress(false);
}
/**
* Shows the progress UI and hides the login form.
*/
public void showProgress(final boolean show) {
loginFormView = activity.findViewById(R.id.login_form);
progressView = activity.findViewById(R.id.login_progress);
int animTime = activity.getResources().getInteger(android.R.integer.config_shortAnimTime);
changeLoginFormVisibility(show, animTime);
changeProgressVisibility(show, animTime);
}
private void changeLoginFormVisibility(final boolean show, final int animTime) {
loginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
loginFormView.animate().setDuration(animTime).alpha(
show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
loginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
});
}
private void changeProgressVisibility(final boolean show, final int animTime) {
progressView.setVisibility(show ? View.VISIBLE : View.GONE);
progressView.animate().setDuration(animTime).alpha(
show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
progressView.setVisibility(show ? View.VISIBLE : View.GONE);
}
});
}
}

View File

@ -1,90 +0,0 @@
package io.github.wulkanowy.activity.main;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.widget.Toast;
import java.io.IOException;
import io.github.wulkanowy.R;
import io.github.wulkanowy.activity.WulkanowyApp;
import io.github.wulkanowy.activity.dashboard.DashboardActivity;
import io.github.wulkanowy.api.Vulcan;
import io.github.wulkanowy.api.login.AccountPermissionException;
import io.github.wulkanowy.api.login.BadCredentialsException;
import io.github.wulkanowy.api.login.NotLoggedInErrorException;
import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.VulcanSynchronization;
import io.github.wulkanowy.services.jobs.GradeJob;
import io.github.wulkanowy.utilities.ConnectionUtilities;
public class LoginTask extends AsyncTask<String, Integer, Integer> {
private Activity activity;
private ProgressDialog progress;
public LoginTask(Activity activity) {
this.activity = activity;
this.progress = new ProgressDialog(activity);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
progress.setTitle(activity.getText(R.string.login_text));
progress.setMessage(activity.getText(R.string.please_wait_text));
progress.setCancelable(false);
progress.show();
}
@Override
protected Integer doInBackground(String... credentials) {
if (ConnectionUtilities.isOnline(activity)) {
VulcanSynchronization vulcanSynchronization = new VulcanSynchronization(new LoginSession());
DaoSession daoSession = ((WulkanowyApp) activity.getApplication()).getDaoSession();
try {
vulcanSynchronization
.loginNewUser(credentials[0], credentials[1], credentials[2], activity, daoSession, new Vulcan());
} catch (BadCredentialsException e) {
return R.string.login_bad_credentials_text;
} catch (AccountPermissionException e) {
return R.string.login_bad_account_permission_text;
} catch (CryptoException e) {
return R.string.encrypt_failed_text;
} catch (NotLoggedInErrorException | IOException e) {
return R.string.login_denied_text;
}
vulcanSynchronization.syncSubjectsAndGrades();
return R.string.login_accepted_text;
} else {
return R.string.noInternet_text;
}
}
protected void onPostExecute(Integer messageID) {
super.onPostExecute(messageID);
GradeJob gradesSync = new GradeJob();
gradesSync.scheduledJob(activity);
progress.dismiss();
Toast.makeText(activity, activity.getString(messageID), Toast.LENGTH_LONG).show();
if (messageID == R.string.login_accepted_text || messageID == R.string.root_failed_text
|| messageID == R.string.encrypt_failed_text) {
Intent intent = new Intent(activity, DashboardActivity.class);
activity.startActivity(intent);
}
}
}

View File

@ -1,111 +0,0 @@
package io.github.wulkanowy.activity.main;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.EditText;
import android.widget.Toast;
import java.util.LinkedHashMap;
import io.github.wulkanowy.R;
public class MainActivity extends AppCompatActivity {
private float mTouchPosition;
private float mReleasePosition;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new AlertDialog.Builder(this)
.setTitle(R.string.warning_label_text)
.setMessage(R.string.warning_text)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
autoComplete();
}
private void autoComplete() {
// Get a reference to the AutoCompleteTextView in the layout
AutoCompleteTextView textView = findViewById(R.id.symbolText);
// Get the string array
String[] countries = getResources().getStringArray(R.array.symbols);
// Create the adapter and set it to the AutoCompleteTextView
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
countries);
textView.setAdapter(adapter);
}
public void login(View a) {
String password = ((EditText) findViewById(R.id.passwordText)).getText().toString();
String email = ((EditText) findViewById(R.id.emailText)).getText().toString();
String symbol = ((EditText) findViewById(R.id.symbolText)).getText().toString();
String[] keys = this.getResources().getStringArray(R.array.symbols);
String[] values = this.getResources().getStringArray(R.array.symbols_values);
LinkedHashMap<String, String> map = new LinkedHashMap<>();
for (int i = 0; i < Math.min(keys.length, values.length); ++i) {
map.put(keys[i], values[i]);
}
if (map.containsKey(symbol)) {
symbol = map.get(symbol);
}
if (!email.isEmpty() && !password.isEmpty() && !symbol.isEmpty()) {
new LoginTask(this).execute(email, password, symbol);
} else {
Toast.makeText(this, R.string.data_text, Toast.LENGTH_SHORT).show();
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mTouchPosition = ev.getY();
}
if (ev.getAction() == MotionEvent.ACTION_UP) {
mReleasePosition = ev.getY();
if (mTouchPosition - mReleasePosition == 0) {
View view = getCurrentFocus();
if (view != null && (ev.getAction() == MotionEvent.ACTION_UP
|| ev.getAction() == MotionEvent.ACTION_MOVE) && view instanceof EditText
&& !view.getClass().getName().startsWith("android.webkit.")) {
int scrcoords[] = new int[2];
view.getLocationOnScreen(scrcoords);
float x = ev.getRawX() + view.getLeft() - scrcoords[0];
float y = ev.getRawY() + view.getTop() - scrcoords[1];
if (x < view.getLeft() || x > view.getRight() || y < view.getTop()
|| y > view.getBottom()) {
((InputMethodManager) this.getSystemService(
Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(
(this.getWindow().getDecorView().getApplicationWindowToken()), 0);
}
}
}
}
return super.dispatchTouchEvent(ev);
}
}

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.activity.started;
package io.github.wulkanowy.activity.splash;
import android.content.Context;
import android.content.Intent;
@ -7,7 +7,7 @@ import android.widget.Toast;
import io.github.wulkanowy.R;
import io.github.wulkanowy.activity.dashboard.DashboardActivity;
import io.github.wulkanowy.activity.main.MainActivity;
import io.github.wulkanowy.activity.login.LoginActivity;
import io.github.wulkanowy.services.jobs.GradeJob;
import io.github.wulkanowy.utilities.ConnectionUtilities;
@ -39,7 +39,7 @@ public class LoadingTask extends AsyncTask<Void, Void, Boolean> {
}
if (context.getSharedPreferences("LoginData", Context.MODE_PRIVATE).getLong("userId", 0) == 0) {
Intent intent = new Intent(context, MainActivity.class);
Intent intent = new Intent(context, LoginActivity.class);
context.startActivity(intent);
} else {
GradeJob gradesSync = new GradeJob();
@ -49,6 +49,5 @@ public class LoadingTask extends AsyncTask<Void, Void, Boolean> {
context.startActivity(intent);
}
}
}

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.activity.started;
package io.github.wulkanowy.activity.splash;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
@ -7,12 +7,12 @@ import android.widget.TextView;
import io.github.wulkanowy.BuildConfig;
import io.github.wulkanowy.R;
public class StartedActivity extends AppCompatActivity {
public class SplashActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_started);
setContentView(R.layout.activity_splash);
TextView versionName = findViewById(R.id.rawText);
versionName.setText(getText(R.string.version_text) + BuildConfig.VERSION_NAME);

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.api;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
@ -8,7 +9,7 @@ import java.util.Map;
public abstract class Api {
protected Cookies cookies;
protected Cookies cookies = new Cookies();
public Cookies getCookiesObject() {
return cookies;
@ -18,20 +19,31 @@ public abstract class Api {
return cookies.getItems();
}
public Cookies setCookies(Map<String, String> cookies) {
this.cookies.setItems(cookies);
return this.cookies;
}
public Cookies addCookies(Map<String, String> cookies) {
this.cookies.addItems(cookies);
return this.cookies;
}
public Document getPageByUrl(String url) throws IOException {
return Jsoup.connect(url)
Connection.Response response = Jsoup.connect(url)
.followRedirects(true)
.cookies(getCookies())
.get();
.execute();
this.cookies.addItems(response.cookies());
return response.parse();
}
public Document postPageByUrl(String url, String[][] params) throws IOException {
Connection connection = Jsoup.connect(url);
for (String[] data : params) {
connection.data(data[0], data[1]);
}
Connection.Response response = connection.cookies(getCookies())
.followRedirects(true)
.method(Connection.Method.POST)
.execute();
this.cookies.addItems(response.cookies());
return response.parse();
}
}

View File

@ -1,10 +1,11 @@
package io.github.wulkanowy.api;
import java.util.HashMap;
import java.util.Map;
public class Cookies {
private Map<String, String> cookies;
private Map<String, String> cookies = new HashMap<>();
public Map<String, String> getItems() {
return cookies;

View File

@ -1,7 +1,5 @@
package io.github.wulkanowy.api;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
@ -55,13 +53,7 @@ public class StudentAndParent extends Api {
}
public void storeContextCookies() throws IOException, NotLoggedInErrorException {
//get context cookie
Connection.Response res = Jsoup.connect(getSnpPageUrl())
.followRedirects(true)
.cookies(getCookies())
.execute();
cookies.addItems(res.cookies());
getPageByUrl(getSnpPageUrl());
}
public String getSnpPageUrl() throws IOException, NotLoggedInErrorException {

View File

@ -27,17 +27,21 @@ public class Vulcan extends Api {
private StudentAndParent snp;
public void login(String email, String password, String symbol)
throws BadCredentialsException, AccountPermissionException, LoginErrorException {
Login login = new Login(new Cookies());
login.login(email, password, symbol);
public void login(Cookies cookies, String symbol) {
this.cookies = cookies;
this.symbol = symbol;
this.cookies = login.getCookiesObject();
}
public void login(String email, String password, String symbol)
throws BadCredentialsException, AccountPermissionException, LoginErrorException, IOException {
Login login = new Login(new Cookies());
String realSymbol = login.login(email, password, symbol);
login(login.getCookiesObject(), realSymbol);
}
public void login(String email, String password, String symbol, String id)
throws BadCredentialsException, AccountPermissionException, LoginErrorException {
throws BadCredentialsException, AccountPermissionException, LoginErrorException, IOException {
login(email, password, symbol);
this.id = id;
@ -52,11 +56,7 @@ public class Vulcan extends Api {
return snp;
}
if (null == id) {
snp = new StudentAndParent(cookies, symbol);
} else {
snp = new StudentAndParent(cookies, symbol, id);
}
snp = createSnp(cookies, symbol, id);
snp.storeContextCookies();
@ -65,6 +65,14 @@ public class Vulcan extends Api {
return snp;
}
public StudentAndParent createSnp(Cookies cookies, String symbol, String id) {
if (null == id) {
return new StudentAndParent(cookies, symbol);
}
return new StudentAndParent(cookies, symbol, id);
}
public AttendanceStatistics getAttendanceStatistics() throws IOException, NotLoggedInErrorException {
return new AttendanceStatistics(getStudentAndParent());
}

View File

@ -38,7 +38,7 @@ public class GradesList {
return getAll("");
}
public List<Grade> getAll(String semester) throws IOException, LoginErrorException, ParseException {
public List<Grade> getAll(String semester) throws IOException, ParseException {
Document gradesPage = snp.getSnPPageDocument(getGradesPageUrl() + semester);
Elements gradesRows = gradesPage.select(".ocenySzczegoly-table > tbody > tr");
Semester currentSemester = snp.getCurrentSemester(snp.getSemesters(gradesPage));

View File

@ -21,7 +21,7 @@ public class SubjectsList {
this.snp = snp;
}
public List<Subject> getAll() throws IOException, LoginErrorException {
public List<Subject> getAll() throws IOException {
Document subjectPage = snp.getSnPPageDocument(subjectsPageUrl);
Elements rows = subjectPage.select(".ocenyZwykle-table > tbody > tr");

View File

@ -1,8 +1,9 @@
package io.github.wulkanowy.api.login;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.parser.Parser;
import org.jsoup.select.Elements;
import java.io.IOException;
@ -11,12 +12,10 @@ import io.github.wulkanowy.api.Cookies;
public class Login extends Api {
private String loginPageUrl = "https://cufs.vulcan.net.pl/{symbol}/Account/LogOn";
private String certificatePageUrl = "https://cufs.vulcan.net.pl/{symbol}"
+ "/FS/LS?wa=wsignin1.0&wtrealm=https://uonetplus.vulcan.net.pl/{symbol}"
+ "/LoginEndpoint.aspx&wctx=https://uonetplus.vulcan.net.pl/{symbol}"
+ "/LoginEndpoint.aspx";
private String loginPageUrl = "https://cufs.vulcan.net.pl/{symbol}/Account/LogOn" +
"?ReturnUrl=%2F{symbol}%2FFS%2FLS%3Fwa%3Dwsignin1.0%26wtrealm%3D" +
"https%253a%252f%252fuonetplus.vulcan.net.pl%252f{symbol}%252fLoginEndpoint.aspx%26wctx%3D" +
"https%253a%252f%252fuonetplus.vulcan.net.pl%252f{symbol}%252fLoginEndpoint.aspx";
private String loginEndpointPageUrl =
"https://uonetplus.vulcan.net.pl/{symbol}/LoginEndpoint.aspx";
@ -25,62 +24,48 @@ public class Login extends Api {
this.cookies = cookies;
}
public boolean login(String email, String password, String symbol)
throws BadCredentialsException, LoginErrorException, AccountPermissionException {
try {
sendCredentials(email, password, symbol);
String[] certificate = getCertificateData(symbol);
sendCertificate(certificate[0], certificate[1], symbol);
} catch (IOException e) {
throw new LoginErrorException();
}
return true;
public String getLoginPageUrl() {
return loginPageUrl;
}
private void sendCredentials(String email, String password, String symbol)
public String getLoginEndpointPageUrl() {
return loginEndpointPageUrl;
}
public String login(String email, String password, String symbol)
throws BadCredentialsException, LoginErrorException, AccountPermissionException, IOException {
String certificate = sendCredentials(email, password, symbol);
return sendCertificate(certificate, symbol);
}
public String sendCredentials(String email, String password, String symbol)
throws IOException, BadCredentialsException {
loginPageUrl = loginPageUrl.replace("{symbol}", symbol);
loginPageUrl = getLoginPageUrl().replace("{symbol}", symbol);
Connection.Response response = Jsoup.connect(loginPageUrl)
.data("LoginName", email)
.data("Password", password)
.method(Connection.Method.POST)
.execute();
Document html = postPageByUrl(loginPageUrl, new String[][]{
{"LoginName", email},
{"Password", password}
});
setCookies(response.cookies());
Document document = response.parse();
if (null != document.select(".ErrorMessage").first()) {
if (null != html.select(".ErrorMessage").first()) {
throw new BadCredentialsException();
}
return html.select("input[name=wresult]").attr("value");
}
private String[] getCertificateData(String symbol) throws IOException {
certificatePageUrl = certificatePageUrl.replace("{symbol}", symbol);
Document certificatePage = getPageByUrl(certificatePageUrl);
return new String[]{
certificatePage.select("input[name=wa]").attr("value"),
certificatePage.select("input[name=wresult]").attr("value")
};
}
private void sendCertificate(String protocolVersion, String certificate, String symbol)
public String sendCertificate(String certificate, String defaultSymbol)
throws IOException, LoginErrorException, AccountPermissionException {
loginEndpointPageUrl = loginEndpointPageUrl.replace("{symbol}", symbol);
String symbol = findSymbol(defaultSymbol, certificate);
Connection.Response response = Jsoup.connect(loginEndpointPageUrl)
.data("wa", protocolVersion)
.data("wresult", certificate)
.cookies(getCookies())
.followRedirects(true)
.method(Connection.Method.POST)
.execute();
loginEndpointPageUrl = getLoginEndpointPageUrl()
.replace("{symbol}", symbol);
addCookies(response.cookies());
Document html = response.parse();
Document html = postPageByUrl(loginEndpointPageUrl, new String[][]{
{"wa", "wsignin1.0"},
{"wresult", certificate}
});
if (html.getElementsByTag("title").text().equals("Logowanie")) {
throw new AccountPermissionException();
@ -89,5 +74,26 @@ public class Login extends Api {
if (!html.select("title").text().equals("Uonet+")) {
throw new LoginErrorException();
}
return symbol;
}
public String findSymbol(String symbol, String certificate) {
if ("Default".equals(symbol)) {
return findSymbolInCertificate(certificate);
}
return symbol;
}
public String findSymbolInCertificate(String certificate) {
Elements els = Jsoup.parse(certificate.replaceAll(":", ""), "", Parser.xmlParser())
.select("[AttributeName=\"UserInstance\"] samlAttributeValue");
if (0 == els.size()) {
return "";
}
return els.get(1).text();
}
}

View File

@ -22,7 +22,7 @@ public class AchievementsList {
this.snp = snp;
}
public List<String> getAllAchievements() throws LoginErrorException, IOException {
public List<String> getAllAchievements() throws IOException {
Element pageFragment = snp.getSnPPageDocument(notesPageUrl)
.select(".mainContainer > div").get(1);
Elements items = pageFragment.select("article");

View File

@ -22,7 +22,7 @@ public class NotesList {
this.snp = snp;
}
public List<Note> getAllNotes() throws LoginErrorException, IOException {
public List<Note> getAllNotes() throws IOException {
Element pageFragment = snp.getSnPPageDocument(notesPageUrl)
.select(".mainContainer > div").get(0);
Elements items = pageFragment.select("article");

View File

@ -17,7 +17,7 @@ public class SchoolInfo {
this.snp = snp;
}
public SchoolData getSchoolData() throws IOException, LoginErrorException {
public SchoolData getSchoolData() throws IOException {
Element e = snp.getSnPPageDocument(schoolPageUrl)
.select(".mainContainer > article").get(0);

View File

@ -3,8 +3,11 @@ package io.github.wulkanowy.api.school;
import java.util.List;
public class TeachersData {
private String className = "";
private String[] classTeacher;
private List<Subject> subjects;
public String getClassName() {

View File

@ -21,7 +21,7 @@ public class TeachersInfo {
this.snp = snp;
}
public TeachersData getTeachersData() throws IOException, LoginErrorException {
public TeachersData getTeachersData() throws IOException {
Document doc = snp.getSnPPageDocument(schoolPageUrl);
Elements rows = doc.select(".mainContainer > table tbody tr");
String description = doc.select(".mainContainer > p").first().text();

View File

@ -25,7 +25,7 @@ public class Timetable {
return getWeekTable("");
}
public Week getWeekTable(String tick) throws IOException, LoginErrorException {
public Week getWeekTable(String tick) throws IOException {
Element table = snp.getSnPPageDocument(timetablePageUrl + tick)
.select(".mainContainer .presentData").first();

View File

@ -20,7 +20,7 @@ public class BasicInformation {
this.snp = snp;
}
public Document getStudentDataPageDocument() throws IOException, LoginErrorException {
public Document getStudentDataPageDocument() throws IOException {
if (null == studentDataPageDocument) {
studentDataPageDocument = snp.getSnPPageDocument(studentDataPageUrl);
}

View File

@ -16,11 +16,11 @@ public class FamilyInformation {
private String studentDataPageUrl = "Uczen.mvc/DanePodstawowe";
public FamilyInformation(StudentAndParent snp) throws IOException, LoginErrorException {
public FamilyInformation(StudentAndParent snp) {
this.snp = snp;
}
public List<FamilyMember> getFamilyMembers() throws IOException, LoginErrorException {
public List<FamilyMember> getFamilyMembers() throws IOException {
Elements membersElements = snp.getSnPPageDocument(studentDataPageUrl)
.select(".mainContainer > article:nth-of-type(n+4)");

View File

@ -27,6 +27,9 @@ public class Account {
@Property(nameInDb = "SYMBOL")
private String symbol;
@Property(nameInDb = "SNPID")
private String snpId;
@ToMany(referencedJoinProperty = "userId")
private List<Subject> subjectList;
@ -45,14 +48,15 @@ public class Account {
@Generated(hash = 335469827)
private transient AccountDao myDao;
@Generated(hash = 1514643300)
public Account(Long id, String name, String email, String password,
String symbol) {
@Generated(hash = 735765217)
public Account(Long id, String name, String email, String password, String symbol,
String snpId) {
this.id = id;
this.name = name;
this.email = email;
this.password = password;
this.symbol = symbol;
this.snpId = snpId;
}
@Generated(hash = 882125521)
@ -104,6 +108,15 @@ public class Account {
return this;
}
public String getSnpId() {
return this.snpId;
}
public Account setSnpId(String snpId) {
this.snpId = snpId;
return this;
}
/**
* To-many relationship, resolved on first access (and after reset).
* Changes to to-many relations are not persisted, make changes to the target entity.

View File

@ -355,9 +355,7 @@ public class Grade implements Parcelable {
myDao.update(this);
}
/**
* called by internal mechanisms, do not call yourself.
*/
/** called by internal mechanisms, do not call yourself. */
@Generated(hash = 1187286414)
public void __setDaoSession(DaoSession daoSession) {
this.daoSession = daoSession;

View File

@ -9,11 +9,10 @@ import io.github.wulkanowy.api.Vulcan;
import io.github.wulkanowy.api.login.AccountPermissionException;
import io.github.wulkanowy.api.login.BadCredentialsException;
import io.github.wulkanowy.api.login.LoginErrorException;
import io.github.wulkanowy.api.login.NotLoggedInErrorException;
import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.services.jobs.VulcanJobHelper;
import io.github.wulkanowy.services.synchronisation.AccountSynchronisation;
import io.github.wulkanowy.services.synchronisation.AccountAuthorization;
import io.github.wulkanowy.services.synchronisation.GradesSynchronisation;
import io.github.wulkanowy.services.synchronisation.SubjectsSynchronisation;
@ -26,18 +25,10 @@ public class VulcanSynchronization {
}
public void loginCurrentUser(Context context, DaoSession daoSession, Vulcan vulcan)
throws CryptoException, BadCredentialsException, AccountPermissionException, IOException, LoginErrorException {
throws CryptoException, BadCredentialsException, AccountPermissionException, LoginErrorException, IOException {
AccountSynchronisation accountSynchronisation = new AccountSynchronisation();
loginSession = accountSynchronisation.loginCurrentUser(context, daoSession, vulcan);
}
public void loginNewUser(String email, String password, String symbol,
Context context, DaoSession daoSession, Vulcan vulcan)
throws BadCredentialsException, NotLoggedInErrorException, AccountPermissionException, IOException, CryptoException {
AccountSynchronisation accountSynchronisation = new AccountSynchronisation();
loginSession = accountSynchronisation.loginNewUser(email, password, symbol, context, daoSession, vulcan);
AccountAuthorization accountAuthorization = new AccountAuthorization(context, daoSession, vulcan);
loginSession = accountAuthorization.loginCurrentUser();
}
public boolean syncGrades() {

View File

@ -1,7 +1,6 @@
package io.github.wulkanowy.services.synchronisation;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import java.io.IOException;
@ -10,8 +9,6 @@ import io.github.wulkanowy.api.Vulcan;
import io.github.wulkanowy.api.login.AccountPermissionException;
import io.github.wulkanowy.api.login.BadCredentialsException;
import io.github.wulkanowy.api.login.LoginErrorException;
import io.github.wulkanowy.api.login.NotLoggedInErrorException;
import io.github.wulkanowy.api.user.PersonalData;
import io.github.wulkanowy.dao.entities.Account;
import io.github.wulkanowy.dao.entities.AccountDao;
import io.github.wulkanowy.dao.entities.DaoSession;
@ -20,9 +17,21 @@ import io.github.wulkanowy.security.Safety;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.jobs.VulcanJobHelper;
public class AccountSynchronisation {
public class AccountAuthorization {
public LoginSession loginCurrentUser(Context context, DaoSession daoSession, Vulcan vulcan) throws CryptoException,
private final Context context;
private final DaoSession daoSession;
private final Vulcan vulcan;
public AccountAuthorization(Context context, DaoSession daoSession, Vulcan vulcan) {
this.context = context;
this.daoSession = daoSession;
this.vulcan = vulcan;
}
public LoginSession loginCurrentUser() throws CryptoException,
BadCredentialsException, AccountPermissionException, IOException, LoginErrorException {
AccountDao accountDao = daoSession.getAccountDao();
@ -38,7 +47,8 @@ public class AccountSynchronisation {
vulcan.login(
account.getEmail(),
safety.decrypt(account.getEmail(), account.getPassword()),
account.getSymbol()
account.getSymbol(),
account.getSnpId()
);
return new LoginSession()
@ -50,36 +60,4 @@ public class AccountSynchronisation {
throw new IOException("Can't find user with index 0");
}
}
public LoginSession loginNewUser(String email, String password, String symbol, Context context, DaoSession daoSession, Vulcan vulcan)
throws BadCredentialsException, NotLoggedInErrorException, AccountPermissionException, IOException, CryptoException {
long userId;
vulcan.login(email, password, symbol);
PersonalData personalData = vulcan.getBasicInformation().getPersonalData();
AccountDao accountDao = daoSession.getAccountDao();
Safety safety = new Safety();
Account account = new Account()
.setName(personalData.getFirstAndLastName())
.setEmail(email)
.setPassword(safety.encrypt(email, password, context))
.setSymbol(symbol);
userId = accountDao.insert(account);
Log.d(VulcanJobHelper.DEBUG_TAG, "Login and save new user id=" + String.valueOf(userId));
SharedPreferences sharedPreferences = context.getSharedPreferences("LoginData", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putLong("userId", userId);
editor.apply();
return new LoginSession()
.setVulcan(vulcan)
.setUserId(userId)
.setDaoSession(daoSession);
}
}

View File

@ -0,0 +1,82 @@
package io.github.wulkanowy.services.synchronisation;
import android.content.Context;
import android.content.SharedPreferences;
import java.io.IOException;
import io.github.wulkanowy.api.Vulcan;
import io.github.wulkanowy.api.login.AccountPermissionException;
import io.github.wulkanowy.api.login.BadCredentialsException;
import io.github.wulkanowy.api.login.Login;
import io.github.wulkanowy.api.login.NotLoggedInErrorException;
import io.github.wulkanowy.dao.entities.Account;
import io.github.wulkanowy.dao.entities.AccountDao;
import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.security.Safety;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.jobs.GradeJob;
public class AccountRegistration {
private final Login login;
private final Vulcan vulcan;
private final String email;
private final String password;
private final String symbol;
public AccountRegistration(Login login, Vulcan vulcan, String email, String password, String symbol) {
this.login = login;
this.vulcan = vulcan;
this.email = email;
this.password = password;
this.symbol = symbol;
}
public String connect()
throws BadCredentialsException, IOException {
return login.sendCredentials(email, password, symbol);
}
public LoginSession login(Context context, DaoSession daoSession, String certificate)
throws NotLoggedInErrorException, AccountPermissionException, IOException, CryptoException {
long userId;
String realSymbol = login.sendCertificate(certificate, symbol);
vulcan.login(login.getCookiesObject(), realSymbol);
AccountDao accountDao = daoSession.getAccountDao();
Safety safety = new Safety();
Account account = new Account()
.setName(vulcan.getBasicInformation().getPersonalData().getFirstAndLastName())
.setEmail(email)
.setPassword(safety.encrypt(email, password, context))
.setSymbol(vulcan.getStudentAndParent().getSymbol())
.setSnpId(vulcan.getStudentAndParent().getId());
userId = accountDao.insert(account);
SharedPreferences sharedPreferences = context.getSharedPreferences("LoginData", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putLong("userId", userId);
editor.apply();
return new LoginSession()
.setVulcan(vulcan)
.setUserId(userId)
.setDaoSession(daoSession);
}
public void scheduleSynchronization(Context context) {
GradeJob gradesSync = new GradeJob();
gradesSync.scheduledJob(context);
}
}

View File

@ -18,7 +18,7 @@ import io.github.wulkanowy.utilities.ConversionVulcanObject;
public class SubjectsSynchronisation {
public void sync(LoginSession loginSession) throws IOException,
ParseException, NotLoggedInErrorException {
NotLoggedInErrorException {
SubjectsList subjectsList = loginSession.getVulcan().getSubjectsList();
SubjectDao subjectDao = loginSession.getDaoSession().getSubjectDao();

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="35dp"
android:height="35dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#000000"
android:pathData="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z" />
<path android:pathData="M0-0.75h24v24H0z" />
</vector>

View File

@ -0,0 +1,155 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:id="@+id/coordinatorLayout"
tools:context="io.github.wulkanowy.activity.login.LoginActivity"
>
<!-- Login progress -->
<RelativeLayout
android:id="@+id/login_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_centerVertical="true"
android:visibility="gone"
>
<ProgressBar
android:id="@+id/login_progress_horizontal"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="91dp"
android:minHeight="30dp"
android:indeterminate="true"
android:minWidth="220dp"
/>
<TextView
android:id="@+id/login_progress_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/login_progress_horizontal"
android:layout_centerHorizontal="true"
android:layout_marginBottom="42dp"
/>
</RelativeLayout>
<ScrollView
android:id="@+id/login_form"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<LinearLayout
android:id="@+id/email_login_form"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/login_heading"
android:layout_marginBottom="24dp"
/>
<android.support.design.widget.TextInputLayout
android:id="@+id/to_email_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
>
<EditText
android:id="@+id/email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/prompt_email"
android:inputType="textEmailAddress"
android:maxLines="1"
android:importantForAutofill="noExcludeDescendants"
/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/to_password_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<EditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/prompt_password"
android:inputType="textPassword"
android:maxLines="1"
android:imeActionLabel="@string/action_sign_in"
android:imeOptions="actionDone"
android:fontFamily="sans-serif"
android:importantForAutofill="noExcludeDescendants"
/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/to_symbol_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
>
<AutoCompleteTextView
android:id="@+id/symbol"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/prompt_symbol"
android:inputType="textAutoComplete"
android:maxLines="1"
android:imeActionLabel="@string/action_sign_in"
android:imeOptions="actionDone"
android:importantForAutofill="noExcludeDescendants"
/>
</android.support.design.widget.TextInputLayout>
<Button
android:id="@+id/action_sign_in"
style="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="24dp"
android:text="@string/action_sign_in"
android:textStyle="bold"
/>
<TextView
android:id="@+id/action_create_account"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/action_create_account"
android:layout_marginBottom="24dp"
/>
<TextView
android:id="@+id/action_forgot_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/action_forgot_password"
/>
</LinearLayout>
</ScrollView>
</RelativeLayout>

View File

@ -1,65 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/appName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="15dp"
android:gravity="center"
android:text="@string/app_name"
android:textSize="40sp" />
<EditText
android:id="@+id/emailText"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:ems="10"
android:hint="@string/email_hint_text"
android:inputType="textEmailAddress" />
<EditText
android:id="@+id/passwordText"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:ems="10"
android:fontFamily="sans-serif"
android:hint="@string/pass_hint_text"
android:inputType="textPassword"
tools:ignore="UnusedAttribute" />
<AutoCompleteTextView
android:id="@+id/symbolText"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:hint="@string/symbol_hint_text"
android:imeOptions="actionDone"
android:inputType="text" />
<Button
android:id="@+id/agreeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:onClick="login"
android:text="@string/login_button_text" />
</LinearLayout>
</ScrollView>

View File

@ -1,18 +1,28 @@
<resources>
<string name="app_name">Wulkanowy</string>
<string name="login_text">Logowanie</string>
<string name="pass_hint_text">Hasło</string>
<string name="email_hint_text">E-mail</string>
<string name="login_button_text">Zaloguj</string>
<string name="symbol_hint_text">Symbol</string>
<string name="warning_text">Aplikacja ta nie jest ukończona, więc mogą występować różnego rodzaju błędy lub dane funkcje nie bedą działać. Prosimy o cierpliwość i wyrozumiałość.</string>
<string name="warning_label_text">Ostrzeżenie</string>
<string name="data_text">Brak danych logowania</string>
<!-- Strings related to login -->
<string name="title_activity_login">Zaloguj się</string>
<string name="login_heading">Zaloguj się za pomocą konta VULCAN</string>
<string name="prompt_email">Email</string>
<string name="prompt_password">Hasło</string>
<string name="prompt_symbol">Symbol</string>
<string name="action_sign_in">Zaloguj</string>
<string name="step_connecting">Łączenie z dziennikiem</string>
<string name="step_login">Logowanie</string>
<string name="step_synchronization">Synchronizacja</string>
<string name="error_invalid_email">Ten adres email nie jest poprawny</string>
<string name="error_invalid_password">To hasło jest za krótkie</string>
<string name="error_incorrect_password">To hasło jest niepoprawne</string>
<string name="error_field_required">To pole jest wymagane</string>
<string name="error_bad_account_permission">Brak dostępu do dziennika. Sprawdź inny symbol</string>
<string name="login_accepted_text">Pomyślnie zalogowano</string>
<string name="login_bad_credentials_text">Niepoprawny e-mail lub hasło</string>
<string name="login_bad_account_permission_text">Brak uprawnień do otwarcia dziennika. Sprawdź wprowadzoną nazwę powiatu</string>
<string name="login_denied_text">Logowanie nie powiodło się</string>
<string name="please_wait_text">Proszę czekać…</string>
<string name="login_denied_text">Logowanie nie powiodło się. Spróbuj zrestartować aplikację</string>
<string name="action_create_account">Nie masz jeszcze konta? Załóż je</string>
<string name="action_forgot_password">Zapomniałeś hasła?</string>
<string name="activity_dashboard_text">Aktywność dashboard</string>
<string name="dashboard_text">Dashboard</string>
<string name="grades_text">Oceny</string>

View File

@ -1,3 +1,7 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View File

@ -1,18 +1,28 @@
<resources>
<string name="app_name">Wulkanowy</string>
<string name="login_text">Login</string>
<string name="pass_hint_text">Password</string>
<string name="email_hint_text">E-mail</string>
<string name="login_button_text">Log in</string>
<string name="symbol_hint_text">Symbol</string>
<string name="warning_text">This application is not complete, so there may be a variety of errors or features that will not work. Please be patient and understanding.</string>
<string name="warning_label_text">Warning</string>
<string name="data_text">No login data</string>
<!-- Strings related to login -->
<string name="title_activity_login">Sign in</string>
<string name="login_heading">Sign in with VULCAN account</string>
<string name="prompt_email">Email</string>
<string name="prompt_password">Password</string>
<string name="prompt_symbol">Symbol</string>
<string name="action_sign_in">Sign in</string>
<string name="step_connecting">Connecting with log</string>
<string name="step_login">Login</string>
<string name="step_synchronization">Synchronization</string>
<string name="error_invalid_email">This email address is invalid</string>
<string name="error_invalid_password">This password is too short</string>
<string name="error_incorrect_password">This password is incorrect</string>
<string name="error_field_required">This field is required</string>
<string name="error_bad_account_permission">No permission to open log. Check another symbol</string>
<string name="login_accepted_text">Login is successful</string>
<string name="login_bad_credentials_text">Bad e-mail or password</string>
<string name="login_bad_account_permission_text">No permission to open log. Check entered symbol</string>
<string name="login_denied_text">Login is failed</string>
<string name="please_wait_text">Please wait…</string>
<string name="login_denied_text">Login is failed. Try restart the app</string>
<string name="action_create_account">No account yet? Create one</string>
<string name="action_forgot_password">Forgot password?</string>
<string name="activity_dashboard_text">Dashboard Activity</string>
<string name="dashboard_text">Dashboard</string>
<string name="grades_text">Grades</string>

View File

@ -31,12 +31,46 @@ public class VulcanTest extends Vulcan {
.thenReturn(snp);
}
@Test(expected = NotLoggedInErrorException.class)
@Test
public void getStudentAndParentTest() throws Exception {
Cookies cookies = new Cookies();
Vulcan vulcan = Mockito.mock(Vulcan.class);
Mockito.when(vulcan.getCookiesObject()).thenReturn(cookies);
StudentAndParent snp = Mockito.mock(StudentAndParent.class);
Mockito.doNothing().when(snp).storeContextCookies();
Mockito.when(snp.getCookiesObject()).thenReturn(cookies);
Mockito.when(vulcan.createSnp( // nullable because method uses class vars, refactor?
Mockito.nullable(Cookies.class), Mockito.nullable(String.class), Mockito.nullable(String.class)
)).thenReturn(snp);
Mockito.when(vulcan.getStudentAndParent()).thenCallRealMethod();
StudentAndParent vulcanSnP = vulcan.getStudentAndParent();
Assert.assertEquals(snp, vulcanSnP);
Assert.assertEquals(vulcanSnP, vulcan.getStudentAndParent());
}
@Test(expected = NotLoggedInErrorException.class)
public void getStudentAndParentNotLoggedInTest() throws Exception {
Mockito.when(vulcan.getStudentAndParent()).thenCallRealMethod();
vulcan.getStudentAndParent();
}
@Test
public void createSnPTest() throws Exception {
Vulcan vulcan = new Vulcan();
vulcan.login(new Cookies(), "testSymbol");
Assert.assertThat(vulcan.createSnp(new Cookies(), "testSymbol", null),
CoreMatchers.instanceOf(StudentAndParent.class));
Assert.assertThat(vulcan.createSnp(new Cookies(), "testSymbol", "testId"),
CoreMatchers.instanceOf(StudentAndParent.class));
}
@Test(expected = NotLoggedInErrorException.class)
public void getAttendanceExceptionText() throws Exception {
Mockito.when(vulcan.getAttendanceTable()).thenCallRealMethod();

View File

@ -1,13 +1,126 @@
package io.github.wulkanowy.api.login;
import static org.junit.Assert.assertEquals;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
import io.github.wulkanowy.api.Cookies;
import io.github.wulkanowy.api.FixtureHelper;
public class LoginTest {
public String getFixtureAsString(String fixtureFileName) {
return FixtureHelper.getAsString(getClass().getResourceAsStream(fixtureFileName));
}
public Login getSetUpLogin(String fixtureFileName) throws Exception {
Document tablePageDocument = Jsoup.parse(getFixtureAsString(fixtureFileName));
Login login = Mockito.mock(Login.class);
Mockito.when(login.postPageByUrl(Mockito.anyString(), Mockito.any(String[][].class))
).thenReturn(tablePageDocument);
Mockito.when(login.getLoginPageUrl()).thenReturn("");
Mockito.when(login.getLoginEndpointPageUrl()).thenReturn("asdf");
return login;
}
@Test
public void login() throws Exception {
assertEquals(4, 2 + 2);
public void loginTest() throws Exception {
Login login = getSetUpLogin("Logowanie-success.html");
Mockito.when(login.login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()))
.thenCallRealMethod();
Mockito.when(login.sendCredentials(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()))
.thenReturn("<xml>");
Mockito.when(login.sendCertificate(Mockito.anyString(), Mockito.anyString())).thenReturn("d123");
Assert.assertEquals("d123", login.login("a@a", "pswd", "d123"));
}
@Test
public void loginDefaultTest() throws Exception {
Login login = getSetUpLogin("Logowanie-success.html");
Mockito.when(login.getLoginEndpointPageUrl()).thenReturn("asdf");
Mockito.when(login.login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()))
.thenCallRealMethod();
Mockito.when(login.sendCredentials(Mockito.anyString(), Mockito.anyString(), Mockito.eq("Default")))
.thenReturn(getFixtureAsString("cert.xml"));
Mockito.when(login.findSymbol(Mockito.anyString(), Mockito.anyString())).thenCallRealMethod();
Mockito.when(login.sendCertificate(Mockito.anyString(), Mockito.anyString())).thenCallRealMethod();
Mockito.when(login.findSymbolInCertificate(Mockito.anyString())).thenCallRealMethod();
Assert.assertEquals("demo12345", login.login("a@a", "pswd", "Default"));
}
@Test(expected = BadCredentialsException.class)
public void sendWrongCredentialsTest() throws Exception {
Login login = getSetUpLogin("Logowanie-error.html");
Mockito.when(login.sendCredentials(
Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenCallRealMethod();
login.sendCredentials("a@a", "pswd", "d123");
}
@Test
public void sendCredentialsCertificateTest() throws Exception {
Login login = getSetUpLogin("Logowanie-certyfikat.html");
Mockito.when(login.sendCredentials(
Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenCallRealMethod();
Mockito.when(login.getLoginPageUrl()).thenReturn("http://a.a");
Assert.assertEquals(
getFixtureAsString("cert.xml").replaceAll("\\s+",""),
login.sendCredentials("a@a", "passwd", "d123").replaceAll("\\s+","")
);
}
@Test
public void sendCertificateNotDefaultSymbolSuccessTest() throws Exception {
Login login = getSetUpLogin("Logowanie-success.html");
Mockito.when(login.findSymbol(Mockito.anyString(), Mockito.anyString())).thenCallRealMethod();
Mockito.when(login.sendCertificate(Mockito.anyString(), Mockito.anyString())).thenCallRealMethod();
Assert.assertEquals("wulkanowyschool321", login.sendCertificate("", "wulkanowyschool321"));
}
@Test
public void sendCertificateDefaultSymbolSuccessTest() throws Exception {
Login login = getSetUpLogin("Logowanie-success.html");
Mockito.when(login.findSymbol(Mockito.anyString(), Mockito.anyString())).thenCallRealMethod();
Mockito.when(login.findSymbolInCertificate(Mockito.anyString())).thenCallRealMethod();
Mockito.when(login.sendCertificate(Mockito.anyString(), Mockito.anyString())).thenCallRealMethod();
Assert.assertEquals("demo12345",
login.sendCertificate(getFixtureAsString("cert.xml"), "Default"));
}
@Test(expected = AccountPermissionException.class)
public void sendCertificateAccountPermissionTest() throws Exception {
Login login = getSetUpLogin("Logowanie-brak-dostepu.html");
Mockito.when(login.findSymbol(Mockito.anyString(), Mockito.anyString())).thenCallRealMethod();
Mockito.when(login.sendCertificate(Mockito.anyString(), Mockito.anyString())).thenCallRealMethod();
login.sendCertificate(getFixtureAsString("cert.xml"), "demo123");
}
@Test(expected = LoginErrorException.class)
public void sendCertificateLoginErrorTest() throws Exception {
Login login = getSetUpLogin("Logowanie-certyfikat.html"); // change to other document
Mockito.when(login.findSymbol(Mockito.anyString(), Mockito.anyString())).thenCallRealMethod();
Mockito.when(login.sendCertificate(Mockito.anyString(), Mockito.anyString())).thenCallRealMethod();
login.sendCertificate(getFixtureAsString("cert.xml"), "demo123");
}
@Test
public void findSymbolInCertificateTest() throws Exception {
Login login = new Login(new Cookies());
String certificate = getFixtureAsString("cert.xml");
Assert.assertEquals("demo12345", login.findSymbolInCertificate(certificate));
}
@Test
public void findSymbolInInvalidCertificateTest() throws Exception {
Login login = new Login(new Cookies());
Assert.assertEquals("", login.findSymbolInCertificate("<xml></xml>")); // change to real cert with empty symbols
}
}

View File

@ -0,0 +1,15 @@
<!doctype html>
<html>
<head>
<title>Logowanie</title>
</head>
<body>
<form id="form1">
<div>
Adres <b>example@wulkanowy.io</b> nie został zarejestrowany w dzienniku uczniowskim jako adres rodzica, bądź ucznia.
Jeśli jesteś rodzicem (prawnym opiekunem) ucznia (lub uczniem) szkoły korzystającej z dziennika „UONET +” udaj się do
wychowawcy i poproś o wprowadzenie Twojego adresu e-mail do Twoich danych.
</div>
</form>
</body>
</html>

View File

@ -0,0 +1,17 @@
<html>
<head>
<title>Working...</title>
</head>
<body>
<form method="POST" name="hiddenform" action="https://fake-log.com/Default/LoginEndpoint.aspx">
<input type="hidden" name="wa" value="wsignin1.0">
<input type="hidden" name="wresult" value="<trust:RequestSecurityTokenResponseCollection xmlns:trust=&quot;http://docs.oasis-open.org/ws-sx/ws-trust/200512&quot;><trust:RequestSecurityTokenResponse Context=&quot;https://uonetplus.fake-log.com/Default/LoginEndpoint.aspx&quot;><trust:RequestedSecurityToken><saml:Assertion AssertionID=&quot;_12345678-1234-1234-1234-1234567890ab&quot; IssueInstant=&quot;2017-10-18T22:00:29.006Z&quot; Issuer=&quot;CUFSTokenService&quot; MajorVersion=&quot;1&quot; MinorVersion=&quot;1&quot; xmlns:saml=&quot;urn:oasis:names:tc:SAML:1.0:assertion&quot;><saml:AttributeStatement><saml:Attribute AttributeName=&quot;UserInstance&quot; AttributeNamespace=&quot;http://schemas.fake-log.com/ws/identity/claims&quot;><saml:AttributeValue>Default</saml:AttributeValue><saml:AttributeValue>demo12345</saml:AttributeValue><saml:AttributeValue>incorrect value</saml:AttributeValue><saml:AttributeValue>warszawa</saml:AttributeValue><saml:AttributeValue>asdf</saml:AttributeValue><saml:AttributeValue>asdfsdf</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion></trust:RequestedSecurityToken></trust:RequestSecurityTokenResponse></trust:RequestSecurityTokenResponseCollection>">
<input type="hidden" name="wctx" value="https://fake-log.com/Default/LoginEndpoint.aspx">
<noscript>
<p>Script is disabled. Click Submit to continue.</p>
<input type="submit" value="Submit">
</noscript>
</form>
<script language="javascript">window.setTimeout('document.forms[0].submit()', 0);</script>
</body>
</html>

View File

@ -0,0 +1,18 @@
<!doctype html>
<html>
<head>
<title>Logowanie (demo123)</title>
</head>
<body>
<div id="MainDiv">
<form>
<div class="ErrorMessage center">
Zła nazwa użytkownika lub hasło
</div>
</form>
</div>
<div id="globalfooter">
<div id="left">16.2.0.4450</div>
</div>
</body>
</html>

View File

@ -0,0 +1,16 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Uonet+</title>
</head>
<body>
<div class="startScreen">
<div class="topBar">
<div class="panelTopBar">
<span class="userdata">example@wulkanowy.io (<a href="/demo123/LoginEndpoint.aspx?logout=true">wyloguj</a>)</span>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,18 @@
<trust:RequestSecurityTokenResponseCollection xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<trust:RequestSecurityTokenResponse Context="https://uonetplus.fake-log.com/Default/LoginEndpoint.aspx">
<trust:RequestedSecurityToken>
<saml:Assertion AssertionID="_12345678-1234-1234-1234-1234567890ab" IssueInstant="2017-10-18T22:00:29.006Z" Issuer="CUFSTokenService" MajorVersion="1" MinorVersion="1" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion">
<saml:AttributeStatement>
<saml:Attribute AttributeName="UserInstance" AttributeNamespace="http://schemas.fake-log.com/ws/identity/claims">
<saml:AttributeValue>Default</saml:AttributeValue>
<saml:AttributeValue>demo12345</saml:AttributeValue>
<saml:AttributeValue>incorrect value</saml:AttributeValue>
<saml:AttributeValue>warszawa</saml:AttributeValue>
<saml:AttributeValue>asdf</saml:AttributeValue>
<saml:AttributeValue>asdfsdf</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</trust:RequestedSecurityToken>
</trust:RequestSecurityTokenResponse>
</trust:RequestSecurityTokenResponseCollection>

View File

@ -1,4 +1,4 @@
#Thu Oct 26 14:47:13 CEST 2017
#Thu Oct 27 17:19:04 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME