Skip to content
blog.fossasia.org
  • Home
  • Projects
    • Contribute
  • Events
    • Eventyay Platform
    • Event Sponsorships
    • Event Calendar
    • FOSSASIA Summit
    • OpenTechSummit China
    • OpenTechSummit Thailand
    • OpenTechSummit Vietnam
    • Jugaad Fest India
    • Past Events
      • FOSSASIA Summit 2022
      • FOSSASIA Summit 2021
      • FOSSASIA Summit 2020
      • FOSSASIA Summit 2019
      • FOSSASIA Summit 2018
      • FOSSASIA Summit 2017
      • FOSSASIA Summit 2016
      • FOSSASIA Summit 2015
      • FOSSASIA Summit 2014
      • FOSSASIA Summit 2012
      • FOSSASIA Summit 2011
      • FOSSASIA Summit 2010
      • GNOME.Asia 2009
      • MiniDebConf Vietnam 2010
      • Sciencehack.Asia
      • Science Hack India
  • Programs
    • Programs and Opportunities
    • Jobs Opportunities
    • Program Guidelines
    • Codeheat Contest
    • University Internship Program
    • University Student Coding Programs
    • High School Student Program
    • Advanced Developer Program
    • Become a Mentor
      • Become A University Student Mentor
      • Become A High School Student Mentor
  • Shop
  • Blog
  • About
    • Jobs
    • Membership
    • Activities
    • Background & Mission
    • Best Practices
    • Licenses
    • Team
    • Code of Conduct
  • Donate
  • Toggle website search
Menu Close
  • Home
  • Projects
    • Contribute
  • Events
    • Eventyay Platform
    • Event Sponsorships
    • Event Calendar
    • FOSSASIA Summit
    • OpenTechSummit China
    • OpenTechSummit Thailand
    • OpenTechSummit Vietnam
    • Jugaad Fest India
    • Past Events
      • FOSSASIA Summit 2022
      • FOSSASIA Summit 2021
      • FOSSASIA Summit 2020
      • FOSSASIA Summit 2019
      • FOSSASIA Summit 2018
      • FOSSASIA Summit 2017
      • FOSSASIA Summit 2016
      • FOSSASIA Summit 2015
      • FOSSASIA Summit 2014
      • FOSSASIA Summit 2012
      • FOSSASIA Summit 2011
      • FOSSASIA Summit 2010
      • GNOME.Asia 2009
      • MiniDebConf Vietnam 2010
      • Sciencehack.Asia
      • Science Hack India
  • Programs
    • Programs and Opportunities
    • Jobs Opportunities
    • Program Guidelines
    • Codeheat Contest
    • University Internship Program
    • University Student Coding Programs
    • High School Student Program
    • Advanced Developer Program
    • Become a Mentor
      • Become A University Student Mentor
      • Become A High School Student Mentor
  • Shop
  • Blog
  • About
    • Jobs
    • Membership
    • Activities
    • Background & Mission
    • Best Practices
    • Licenses
    • Team
    • Code of Conduct
  • Donate
  • Toggle website search

login

Read more about the article Overwriting uid for Root User in Meilix

Overwriting uid for Root User in Meilix

  • Post author:meets2tarun
  • Post published:August 24, 2018
  • Post category:FOSSASIA/GSoC/Meilix
  • Post comments:0 Comments

Meilix is known for its customisation feature. There is a folder meilix-default-settings with the help of which we can overwrite system configuration.

Problem:

Meilix has a login issue so it happened that uid assigned to hotelos is 999 whereas the login manager accept uid 1000. We tried to change the uid using system configuration but it doesn’t get change.

Solution:

We thought of different approach to overwrite the uid file with uid of hotelos 1000. The default file can be found at etc/passwd

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
syslog:x:104:108::/home/syslog:/bin/false
_apt:x:105:65534::/nonexistent:/bin/false
messagebus:x:106:110::/var/run/dbus:/bin/false
uuidd:x:107:111::/run/uuidd:/bin/false
sddm:x:108:114:Simple Desktop Display Manager:/var/lib/sddm:/bin/false
lightdm:x:109:115:Light Display Manager:/var/lib/lightdm:/bin/false
avahi:x:110:117:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
colord:x:111:120:colord colour management daemon,,,:/var/lib/colord:/bin/false
dnsmasq:x:112:65534:dnsmasq,,,:/var/lib/misc:/bin/false
pulse:x:113:121:PulseAudio daemon,,,:/var/run/pulse:/bin/false
rtkit:x:114:123:RealtimeKit,,,:/proc:/bin/false
usbmux:x:115:46:usbmux daemon,,,:/var/lib/usbmux:/bin/false
jvb:x:999:1000::/usr/share/jitsi-videobridge:/bin/bash
jicofo:x:998:1000::/usr/share/jicofo:/bin/bash
prosody:x:116:125:Prosody XMPP Server,,,:/var/lib/prosody:/bin/false
hotelos:x:1000:1001:hotelos,,,:/home/tarun:/bin/bash

 

Through this we can see that the root get the uid 0 and the user get uid 1000.

This approach made the uid 1000 but the OS doesn’t bypass the login issue because we found that jitsi-meet installer caused the issue. It creates two user, one is jwb and other is jicofu. Due to this reason our etc/passwd is also not working as it conflicts the existing user.

This line present in scripts/chroot.sh install the jitsi-meet.

wget -qO - https://download.jitsi.org/jitsi-key.gpg.key | apt-key add -

This line add the entry into the source.list.d file for the jitsi-meet

sudo sh -c "echo 'deb https://download.jitsi.org stable/' > /etc/apt/sources.list.d/jitsi-stable.list"

Finally this line install jitsi-meet.

apt-get -y install jitsi-meet

We need to remove all these lines for removing jitsi-meet to get the meilix-default-settings work again.

Reference:

Jitsi-meet

Uid

Continue ReadingOverwriting uid for Root User in Meilix
Read more about the article Integrating smart lock for passwords on Android [Storing user’s credentials]

Integrating smart lock for passwords on Android [Storing user’s credentials]

  • Post author:Arundhati Gupta
  • Post published:August 21, 2018
  • Post category:Android/FOSSASIA/GSoC/SUSI.AI
  • Post comments:0 Comments

“Imagine you have an amazing app in the market. You are really excited to test it and use it for simplifying life. You just downloaded the app. The colorful intro screens only add to your expectations. Finally, you end up on the login screen. You now want to login to the app. You type in your email and password. But, oh! You  have entered an invalid password. No issues! You have a cool option to reset your password. You went to the reset password option and again you had to enter your email address. Congratulations, you have successfully reset your password. Now, you again open the app and you see the login screen. Again, you are asked to enter your credentials. Well! I am sure, by now, you are annoyed! I hope you are not planning to uninstall the app….. 🙁 ”

In real world, every user wants things to be done quickly. Auto-correction and auto-fill are examples of such  utilities that make things convenient for the user. Similarly, login credentials too can be auto filled into the required fields to make login quicker and more convenient for the user. For this, Android offers smart lock feature. By integrating Smart Lock for Passwords into your Android app, you can automatically sign users in to your app using the credentials they have saved. Users can save both username-password credentials and federated identity provider credentials.

After users successfully sign in, create accounts, or change passwords, they can be allowed to store their credentials to automate future authentication in the app.

Store Credentials

Step – 1 : Create a Credential object containing a user’s sign-in information.

Credential credential = new Credential.Builder(email)
        .setPassword(password).build();


Step – 2 :
Call CredentialsClient.save() to save users’ credentials.

Note: This call might not be immediately successful. If this is the case, then it means the credentials might be new. In this case, the user must confirm the save request. Thus, Resolve the ResolvableApiException with startResolutionForResult() to prompt the user for confirmation.

If the user chooses not to save credentials, the user won’t be prompted again to save any account’s credentials for the app. If the  CredentialsClient.save()  is called after a user has opted out, its result will have a status code of CANCELED.

If the user wants to save the credentials at some point of time in future then s/he can opt in later from the Google Settings app, in the Smart Lock for Passwords section. Now, the user must enable credential saving for all accounts to be prompted to save credentials next time.

mCredentialsClient.save(credential).addOnCompleteListener(
        new OnCompleteListener() {
            @Override
            public void onComplete(@NonNull Task task) {
                if (task.isSuccessful()) {
                    Log.d(TAG, "SAVE: OK");
                    Toast.makeText(this, "Credentials saved", 
                                     Toast.LENGTH_SHORT).show();
                    return;
                }

                Exception e = task.getException();
                if (e instanceof ResolvableApiException) {
                    // Try to resolve the save request. 
                    //This will prompt the user if
                    // the credential is new.
                    ResolvableApiException rae = (ResolvableApiException) e;
                    try {
                        rae.startResolutionForResult(this, RC_SAVE);
                    } catch (IntentSender.SendIntentException e) {
                        // Could not resolve the request
                        Log.e(TAG, "Failed to send resolution.", e);
                        Toast.makeText(this, "Save failed",           
                                        Toast.LENGTH_SHORT).show();
                    }
                } else {
                    // Request has no resolution
                    Toast.makeText(this, "Save failed",         
                                   Toast.LENGTH_SHORT).show();
                }
            }
        });

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    // ...

    if (requestCode == RC_SAVE) {
        if (resultCode == RESULT_OK) {
            Log.d(TAG, "SAVE: OK");
            Toast.makeText(this, "Credentials saved",        
                                Toast.LENGTH_SHORT).show();
        } else {
            Log.e(TAG, "SAVE: Canceled by user", e);
        }
    }

    // ...

}


After storing, the credentials can be retrieved by calling
CredentialsClient.request()

In this way, you can store user’s credentials to auto fill the credentials on the login screen. This saves user’s time and adds to the user experience. This will also be implemented in SUSI.AI alongwith an improved auth flow for a better user experience.

Resources

  • Smart lock for passwords on Android
    https://developers.google.com/identity/smartlock-passwords/android/
Continue ReadingIntegrating smart lock for passwords on Android [Storing user’s credentials]
Read more about the article Making the Login fragment in the Open Event Android App

Making the Login fragment in the Open Event Android App

  • Post author:nikit19
  • Post published:July 19, 2018
  • Post category:Android/Event Management/FOSSASIA/GSoC/Open Event
  • Post comments:0 Comments

The first thing that was implemented in the Open Event Android app was the login screen. This is because there were many API endpoints which cannot be accessed without an auth token. Let’s see how this was implemented.

JWT token

Firstly let’s talk about what is this token that I mentioned. The token is JWT (Javascript Web Token) which includes certain information about the user, such as identifier and information about if the token is valid, when will it expire and a signature to verify if it was tampered.

Code

Let’s have a look at the code in the Login fragment. Firstly we have a boolean to check if the user should login or not. If this variable is true we will send the user to the MainActivity. Next if the user clicks on the login button we will check the username and password and then the we will decide whether to show the progress bar or not. If the user encounters an error while logging in that error is shown to the user in a toast message.

if (loginActivityViewModel.isLoggedIn())

redirectToMain()

rootView.loginButton.setOnClickListener {

loginActivityViewModel.login(username.text.toString(), password.text.toString())

}

loginActivityViewModel.progress.observe(this, Observer {

it?.let { showProgress(it) }

})

loginActivityViewModel.error.observe(this, Observer {

Toast.makeText(context, it, Toast.LENGTH_LONG).show()

})

loginActivityViewModel.loggedIn.observe(this, Observer {

Toast.makeText(context, “Success!”, Toast.LENGTH_LONG).show()

redirectToMain()

})

All these methods and variables are declared in the ViewModel so let’s have a look there to understand them. All our variables are of the type LiveData, this is the reason why we are using the observe method in the login fragment. The observe method is used to observe these variables and whenever their value is changed it notifies the observer. In the login function we are sending a request to the server in a background thread.

val progress = MutableLiveData<Boolean>()

val error = SingleLiveEvent<String>()

val loggedIn = SingleLiveEvent<Boolean>()

fun isLoggedIn() = authService.isLoggedIn()

fun login(email: String, password: String) {

if (email.isNullOrEmpty() || password.isNullOrEmpty()) {

error.value = “Email or Password cannot be empty”

return

}

compositeDisposable.add(authService.login(email, password)

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.doOnSubscribe {

progress.value = true

}.doFinally {

progress.value = false

}.subscribe({

loggedIn.value = true

}, {

error.value = “Unable to Login. Please check your credentials”

}))

}

Finally lets have a look at the login function of the AuthService class that was used above. We will throw an exception if the username or password is empty. Otherwise we will send a POST request to the server with the username and password. Then we will store the JWT access token which will be used when we will access the endpoints of the server.

fun login(username: String, password: String): Single<LoginResponse> {

if (username.isEmpty() || password.isEmpty())

throw IllegalArgumentException(“Username or password cannot be empty”)

return authApi.login(Login(username, password))

.map {

authHolder.token = it.accessToken

it

}

}

This is how the POST request for login looks

@POST(“../auth/session”)

fun login(@Body login: Login): Single<LoginResponse>

This all that is required to create the login fragment.

Resources

  1. ReactiveX official documentation : http://reactivex.io/
  2. Vogella RxJava 2 – Tutorial : http://www.vogella.com/tutorials/RxJava/article.html
  3. JWT token Wikipedia: https://en.wikipedia.org/wiki/JSON_Web_Token
Continue ReadingMaking the Login fragment in the Open Event Android App
Read more about the article How Anonymous Mode is Implemented in SUSI iOS
How Anonymous Mode is Implemented in SUSI iOS

How Anonymous Mode is Implemented in SUSI iOS

  • Post author:Jogendra Kumar
  • Post published:July 15, 2018
  • Post category:FOSSASIA/GSoC/SUSI.AI
  • Post comments:0 Comments

Anonymous Login is an easy way for people to try an app without sharing any of their personal information. Sometimes people want to try out apps, but they’re not ready to share any information about themselves. For this, SUSI introduced a way to log in to apps anonymously.

In SUSI iOS we use login and signup to save user’s messages, preferences, settings and secure messages from others. There are Login and Sign up features presents in SUSI iOS app. But the user can also use the app without logging in. Here I will show you, how the anonymous mode implemented in SUSI iOS.

The user can use app either by login using username and password or anonymously by clicking the skip button.

At the time of the login process, we store the user’s data in User object with `accessToken` and during `signout` process we remove the user key from `UserDefaults`. User Defaults is an interface to the user’s defaults database, where user store key-value pairs persistently across launches of the app.

When the user enters in anonymous mode by clicking the Skip button, `currentUser: user` object set to the nil.

Here is how the skip button action implemented in LoginViewController:

  • Delete the current Realm database from the device
  • Delete the trained voice model from the device
  • Reset all settings to default settings
  • Set SUSI API URL as server URL
  • Enter into chat screen
@objc func enterAnonymousMode() {
resetDB()
deleteVoiceModel()
resetSettings()
UserDefaults.standard.set(Client.APIURLs.SusiAPI, forKey: ControllerConstants.UserDefaultsKeys.ipAddress)
completeLogin()
}

When the user enters into the Login screen, we check the existing session by `checkSession()` method:

func checkSession() {
if let userDefaultValue = UserDefaults.standard.value(forKey: ControllerConstants.UserDefaultsKeys.user) {
if let userData = userDefaultValue as? [String: AnyObject] {
let user = User(dictionary: userData)
saveUserGlobally(user: user)

DispatchQueue.main.async {
if user.expiryTime > Date() {
self.completeLogin(false)
self.fetchUserSettings(user.accessToken)
} else {
self.resetDB()
    }
   }
  }
 }
}

Save user globally so that it can be checked anytime whether the user is logged in or entered anonymously by `currentUser` value nil or not. In the case of anonymous mode, `currentUser` is nil.

func saveUserGlobally(user: User) {
 if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
  appDelegate.currentUser = user
 }
}

The user can always login into the app. If the user is using the app in anonymous mode but he/she want to login then he/she can log in. There is an option for login in Settings Menu.

Clicking on login button, direct user to Login screen where the user can log in with registered email and password.

Resources –

  1. User Defaults: https://developer.apple.com/documentation/foundation/userdefaults
  2. App Delegate: https://developer.apple.com/documentation/uikit/uiapplicationdelegate?hl=et
  3. SUSI iOS Link: https://github.com/fossasia/susi_iOS
Continue ReadingHow Anonymous Mode is Implemented in SUSI iOS
Read more about the article Configuring Firebase in Loklak Search

Configuring Firebase in Loklak Search

  • Post author:simsausaurabh
  • Post published:July 6, 2018
  • Post category:FOSSASIA/GSoC/loklak
  • Post comments:0 Comments

In process of expanding features of loklak to provide support of twitter api to the users, it was a good idea to go with Firebase as the managing medium for logged in or authenticated users. After integration of Firebase into loklak, users will be able to authenticate themselves securely with Facebook, Google, and Twitter and get access to the results from Twitter api on loklak. In this blog post, I will be discussing the Firebase configuration process into loklak.

Setting up Firebase environment configuration

Without explicitly going into each single detail of the integration process which is already provided by Firebase and other mediums, I will jump on to the main key characteristics of configuring Firebase into Loklak. This step covers the configuration of Firebase environment parameters. Goto Firebase console and copy the project’s environment’s parameters for web app option and paste it into environments/environment.ts file inside the project as given below by replacing all ‘*’ with the required values.

export const environment = {
    production: true,
    firebase: {
    apiKey: ‘***’,
    authDomain: ‘***’,
    databaseURL: ‘***’,
    projectId: ‘***’,
    storageBucket: ‘***’,
    messagingSenderId: ‘***’
    }
};

Initialise the Firebase app

Next step would be to cover establish the Firebase app in app.module.ts by importing necessary packages as given below.

import { AngularFireModule } from ‘angularfire2’;
import { AngularFirestoreModule } from ‘angularfire2/firestore’;
import { AngularFireAuthModule } from ‘angularfire2/auth’;
import { environment } from ‘../environments/environment’; 

...
imports: [
  …
  AngularFireModule.initializeApp(environment.firebase,
    ‘loklak-search’),
  AngularFirestoreModule,
  AngularFireAuthModule
]

Creating Auth service with various Auth providers

This is the main part of the Firebase configuration. Create a new Auth service in ‘services/’, and include the given below methods for providing authentication using – Twitter, Facebook, Google, and Email & Password. We will also provide logout feature for the user to log out from the current service provider. Given below is an example of adding Google as the service provider for authentication, it can be similarly used to provider authentication for other providers.

import { Injectable } from ‘@angular/core’;
import { AngularFireAuth } from ‘angularfire2/auth’;
import { Observable } from ‘rxjs’;
import * as firebase from ‘firebase/app’;

@Injectable()
export class AuthService {

    public authState: Observable<firebase.User>;
    constructor( private afAuth: AngularFireAuth ) {
        this.authState = this.afAuth.authState;
    }

    signInWithGoogle() {
        return this.afAuth.auth.signInWithPopup(
            new firebase.auth.GoogleAuthProvider()
        );
    }

    logout() {
        this.afAuth.auth.signOut();
    }
}

 

We are using AngularFireAuth to provide authentication for every provider.

Using Auth service in the required component

This step would cover up the last portion to use the auth service to actually provide authenticated login. Now, import the created auth service and other packages and create a property of auth service and a user variable to keep check on the current user status (We would store the current status on the constructor call).

import { AuthService } 
    from ‘./../services/auth.service’;
import * as firebase from ‘firebase/app’;
…
public user: Observable<firebase.User>;
    constructor(
        private _eref: ElementRef,
        private afAuth: AuthService
    ) {
        this.user = this.afAuth.authState;
    }

 

Now, call the methods of auth service and storing the status of current user in the user property created above (For an example, calling only twitter auth and logout method).

signInWithTwitter() {
    this.afAuth.signInWithTwitter();
}
logout() {
    this.afAuth.logout();
}

 

These methods could now be easily called inside (click) property of any appropriate html div/tag to provide login or logout feature.

Testing Auth Login

Click on the div/tag which is calling the SignIn methods and look onto the console for results.

Resources

  • Firebase: Getting Started
  • Firebase: Firebase Authentication Providers
  • ITNEXT: Firebase Authentication
Continue ReadingConfiguring Firebase in Loklak Search
Read more about the article Introduction to MVP in SUSI Android App

Introduction to MVP in SUSI Android App

  • Post author:chiragw15
  • Post published:July 23, 2017
  • Post category:Android/FOSSASIA/GSoC/SUSI.AI/Tutorial
  • Post comments:0 Comments

Recently in SUSI Android app, we started shifting to MVP Design Pattern. We have shifted some part of it and some part is remaining and will be shifted soon. In this blog post, I am not going to tell you about “What is MVP”. Neither will I talk about advantages and disadvantages of using MVP design pattern over other design patterns. There are many good blogs by very experienced Android Developers about the same on the internet (Some good resources at the end of this blog). Rather in this post, I will talk about how to shift your already written app code to MVP design steadily without breaking the app. Also if you are willing to contribute in SUSI Android app, this post will guide you a little about how the things are been implemented and explains the code a little.

Brief Intro

I will not go into detail about MVP Design but just a formal introduction and explanation of some terms that will make you understand the blog post better. If you want to go into details, I have added resources at the bottom, read those. So, MVP stands for Model View Presenter. Initially when you write code for an Android app, what you do is make an XML file storing all views and design and a Java Class storing everything else, which may include sending a request over the Internet, fetching through databases, updating views, etc.

But in MVP design, the logic for getting data like network request and UI updates like showing the data is separated. As the name suggests, MVP has three components:

  1. Model: A Model is a place where the code for all the business logic is written. It includes making network calls, fetching data from the database etc.
  2. View: All the UI updates like showing data, showing dialog boxes and errors, taking inputs from click listeners, animations etc are done here.
  3. Presenter: This acts as a middleman between View and Model. Takes input from View, gives it to Model. Takes data from Model and gives back to the View.

The Process goes like this

I have made this schematic to explain things better.

Implementation

Let’s take the example of Login functionality and go step by step to convert it to MVP Design Pattern.

Requirements

Before starting, make a new package named “login” and add following 6 files in it:

  1. ILoginView -> Interface
  2. ILoginPresenter -> Interface
  3. ILoginModel -> Interface
  4. LoginActivity -> Class
  5. LoginPresenter -> Class
  6. LoginModel  -> Class

Explanation

Let’s see what the above files do. Just remember, the main aim of MVP Pattern is to keep business logic separate from UI Updates.

LoginActivity -> Takes input and Makes UI Updates. Asks LoginPresenter to do word using ILoginPresenter Interface.

LoginPresenter -> Acts as a presentation layer which does all checks on data and invokes LoginModel using ILoginModel interface and in return asks LoginActivity to update UI using ILoginView interface.

LoginModel -> Stores all business logic like making network calls and fetching data. Notifies LoginPresenter about success using OnLoginFinishedListener.

I have divided the process of login 5 steps:

1. In the LoginActivity, this below code snippet takes input email, password and login URL (SUSI default or custom) and asks the presenter to login using ILoginPresenter interface.

fun startLogin() {
   val stringEmail = email.editText?.text.toString()
   val stringPassword = password.editText?.text.toString()
   val stringURL = input_url.editText?.text.toString()
   loginPresenter.login(stringEmail, stringPassword, susi_default.isChecked, this, stringURL)
}

2. In LoginPresenter, all checks like whether the email is empty or password is empty or email is not a valid email etc. If anything is not valid, then it notifies the LoginActivity using ILoginView interface to show that error. When it is confirmed that everything is correct, the presenter then asks model using ILoginModel interface to make a network call.

override fun login(email: String, password: String, isSusiServerSelected: Boolean, context: Context, url: String) {
   if (email.isEmpty()) {
       loginView?.invalidCredentials(true, Constant.EMAIL)
       return
   }

   if(password.isEmpty()) {
       loginView?.invalidCredentials(true, Constant.PASSWORD)
       return
   }

   if (!CredentialHelper.isEmailValid(email)) {
       loginView?.invalidCredentials(false, Constant.EMAIL)
       return
   }

   this.email = email
   this.context = context
   loginView?.showProgress(true)
   loginModel.login(email.trim({ it <= ' ' }).toLowerCase(), password, this)
}
  1. Now LoginModel makes the network call using below code snippet and notifies success or failure to LoginPresenter using OnLoginFinishedListener.
override fun login(email: String, password: String, listener: ILoginModel.OnLoginFinishedListener) {

   authResponseCall = ClientBuilder().susiApi
           .login(email, password)

   authResponseCall.enqueue(object : Callback<LoginResponse> {
       override fun onResponse(call: Call<LoginResponse>, response: Response<LoginResponse>) {
           listener.onSuccess(response)
       }

       override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
           t.printStackTrace()
           listener.onError(t)
       }
   })
}
  1. Now presenter has been notified that whether the login network call was a success or a failure.

4.1 Success:  If Network call was made successfully, LoginPresenter checks whether the response from SUSI Server was “Okay!! Allow a user to enter” or “NO!! The password you entered is invalid” and then asks LoginActivity to act accordingly.

override fun onSuccess(response: Response<LoginResponse>) {

   loginView?.showProgress(false)

   if (response.isSuccessful && response.body() != null) {

       loginView?.onLoginSuccess(response.body().message)
 
  } else if (response.code() == 422) {
       loginView?.onLoginError(context.getString(R.string.password_invalid_title),
               context.getString(R.string.password_invalid))
   } else {
       loginView?.onLoginError("${response.code()} " + context.getString(R.string.error), response.message())
   }
}

4.2 Failure: If Network call was a failure due to reasons like SocketTimeOutException or UnknownHostException etc. then onError is called in LoginPresenter which checks what is the cause and invokes LoginActivity to take action accordingly.

override fun onError(throwable: Throwable) {
   loginView?.showProgress(false)

   if (throwable is UnknownHostException) {
       loginView?.onLoginError(context.getString(R.string.unknown_host_exception), throwable.message.toString())
   } else {
       loginView?.onLoginError(context.getString(R.string.error_internet_connectivity),
               context.getString(R.string.no_internet_connection))
   }
}
  1. Everything is done. We just need to update the UI based on success or failure of login.

5.1 Success : When login is successful, LoginActivity is finished and MainActivity is started.

override fun onLoginSuccess(message: String) {
   Toast.makeText(this@LoginActivity, message, Toast.LENGTH_SHORT).show()
   val intent = Intent(this@LoginActivity, MainActivity::class.java)
   intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
   intent.putExtra(Constant.FIRST_TIME, true)
   startActivity(intent)
   finish()
}

5.2 Failure: If login is not successful, then Alert dialog box is displayed.

override fun onLoginError(title: String?, message: String?) {
   val notSuccessAlertboxHelper = AlertboxHelper(this@LoginActivity, title, message, null, null, getString(R.string.ok), null, Color.BLUE)
   notSuccessAlertboxHelper.showAlertBox()
}

Summary

Though this post does not contain all the basic stuff required to learn MVP and it its advantages of other Design Patterns but it gives you a pretty decent idea about what exactly you need to do in order to shift your already written code to MVP design. Just remember these 3 simple rules.

  1. Make View as dumb as possible. It should not contain any logic at all.
  2. Add all the logic to Model. No UI update should be made from Model.
  3. There should be no direct relation between Model and View. Presenter act as a middle man. Everything should pass from it.

If you follow these three points, MVP is easy to understand and implement.

Resources

  1. A blog/tutorial on MVP by Antonio Leiva: https://antonioleiva.com/mvp-android/
  2. A blog on MVP/tutorial by Francesco Cervone: https://medium.com/@cervonefrancesco/model-view-presenter-android-guidelines-94970b430ddf
  3. A blog/tutorial on MVP by Nitin Agarwal: https://android.jlelse.eu/android-mvp-for-beginners-25889c500443
  4. A blog/tutorial by Tin Megali: https://code.tutsplus.com/tutorials/an-introduction-to-model-view-presenter-on-android–cms-26162
  5. Youtube videos to learn MVP by Dave Kavanagh: https://www.youtube.com/playlist?list=PLLaRyV1pLh_iL47JzywLVmBvEwxeeKOLl
Continue ReadingIntroduction to MVP in SUSI Android App
Read more about the article How Authentication works in the Ember JS Open Event Frontend

How Authentication works in the Ember JS Open Event Frontend

  • Post author:CosmicCoder96
  • Post published:July 14, 2017
  • Post category:FOSSASIA/Open Event
  • Post comments:0 Comments

After decoupling of the frontend and backend where in Open Event Orga Server has been transformed into  JSON:API Spec Compliant REST API , the front end resides in Open Event Frontend, and this blog post illustrates how the login and authentication works on Open Event Frontend using the new API.

First, we will briefly explore the UI of the login form, it’s a standard login form, with the ability to display errors in case something goes wrong. Like all forms it is stored in it’s separate component. With two fields an email and a password. Brief discussion of the UI is important since the field names will be the same ones used for fetching values making requests to the API. In case there is an error, for instance wrong credentials, it gets passed to the errorMessage property of the component. For entire code for the UI of the form, please refer to the Resources section at the end  of the blog. The only relevant details which we need from the UI are the names of the fields, which are email and password respectively.And that the login button triggers the submit action of the form.

So we begin our discussion with a brief description of the package which manages the authentication in Open Event Front End. ember-simple-auth  has been used to manage all the authentication needs, including maintaining the current user session. To quote it’s official documentation it helps us achieve the following goals in our project among it’s many other capabilities which are not being used here :

  • it maintains a client side session and synchronises its state across multiple tabs/windows of the application
  • it authorises requests to backend servers

In addition to ember-simple-auth we make use of ember-simple-auth-token which is an extension to ember-simple-auth library. It provides the token authenticator and thus handles communicating with the backend to receive a token successfully.

Next we need to configure the above two libraries, to connect to our API located at open-event-api.herokuapp.com The documentation tells us exactly what routes we need, in our case we need to make a POST request to the route  /auth/session  and pass in email and password in the body. The Content-Type should be specified as application/json.   If everything goes well, we should receive a JWT access token in response.To configure the libraries, we specify the following in  config/environment.js file.

ENV['ember-simple-auth'] = {
authorizer: 'authorizer:jwt'
};
ENV['ember-simple-auth-token'] = {
refreshAccessTokens      : false,
serverTokenEndpoint      : `${ENV.APP.apiHost}/auth/session`,
identificationField      : 'email',
passwordField            : 'password',
tokenPropertyName        : 'access_token',
refreshTokenPropertyName : 'refresh_token',
authorizationPrefix      : 'JWT ',
authorizationHeaderName  : 'Authorization',
headers                  : {}
};

So we begin our discussion from the point where user has entered the credentials and presses the login button which triggers the submit action. Following is the code for the submit action and we will examine each section of it in this article.

submit() {
this.onValid(() => {
  let credentials = this.getProperties('identification', 'password'),
    authenticator = 'authenticator:jwt';

  this.set('errorMessage', null);
  this.set('isLoading', true);

  this.get('session')
    .authenticate(authenticator, credentials)
    .then(() => {
      const tokenPayload = this.get('authManager').getTokenPayload();
      if (tokenPayload) {
        this.get('store').findRecord('user', tokenPayload.identity).then(user => {
          this.get('session').set('data.currentUser', user);
        });
      }
    })
    .catch(reason => {
      if (reason.hasOwnProperty('status_code') && reason.status_code === 401) {
        this.set('errorMessage', this.l10n.t('Your credentials were incorrect.'));
      } else {
        this.set('errorMessage', this.l10n.t('An unexpected error occurred.'));
      }
      this.set('isLoading', false);
    })
  });
}

this.onValid()  ensures that the rest of the action is executed only if the values entered by the user pass the basic form validations. Using getProperties, the values entered by the user are stored in credentials. Next, the authenticator is specified and isLoading is set to true to show the loading icon while the request is processed. And then we use the authenticate method of ember simple auth  to validate the credentials. If the authentication is successful, the then clause executes and we fetch the correct  user from the model using tokenPayload which contains the required information in the form of it’s identity  property and set it as the current user for the session.

However if the authentication fails, the catch block executes.  The API is configured to return the correct status code 401, in case the credentials were wrong, in which case the errorMessage is set to the appropriate response. The else clause handles all other cases where authentication fails and gives a generic error message. Finally the isLoading  is set to false. And if the authentication was successful, the user is redirected to the index route else, stays on the same route with the error message.

 

Resources

  • Ember JS
  • Ember simple auth
  • Ember simple auth token
  • Open Event API Docs
  • Open Event Front End Login Form template
  • JSON:API Spec
Continue ReadingHow Authentication works in the Ember JS Open Event Frontend

Sharing Images on Facebook from Phimpme Android App

  • Post author:Subhankar29
  • Post published:June 28, 2017
  • Post category:Android/API/FOSSASIA/GSoC/Tutorial
  • Post comments:0 Comments

In Phimpme Android app, our next objective was to share the image to the Social media platform. As Facebook being the largest social media platform it is easier to reach many people through it. Below are the steps we followed to implement sharing an image on Facebook.

Step 1

First, we need to setup our android application development environment. We need to add Facebook SDK for android to the environment.

This can either be done by downloading Facebook SDK or directly adding it to the gradle.

In Phimpme we have used the latter(adding facebook sdk through gradle).

Add this to your build.gradle file before depencies:

repositories {
  mavenCentral() 
}

And add this in your dependencies:

compile 'com.facebook.android:facebook-android-sdk:4.23.0'

We, can use any sdk after 4+ but 4.23.0 is the latest when Phimpme Android was in development.

Step 2

For every application which is under development Facebook requires the user to create a Facebook App ID. This can be done by logging to https://developers.facebook.com/apps and then creating the app. This will generate an APP ID on the dashboard.

We need add this App ID to our android development environment. In Strings.xml (app/src/main/res/values/strings.xml.) Add a new String of the name facebook_app_id and the value should be the facebook app id which was generated in the https://developers.facebook.com/apps dashboard.

<string name="facebook_app_id">1920575401558694</string>

Step 3

Generating Key Hash and adding the hash key to the https://developers.facebook.com/apps. This Key Hash is required to communicate information between the app and Facebook.

To generate the Key Hash run the following command in the terminal in the development directory.

keytool -exportcert -alias <RELEASE_KEY_ALIAS> -keystore <RELEASE_KEY_PATH> | openssl sha1 -binary | openssl base64

Where release key should be replaced with app id and the path of the release key path. This will generate a string which we have to paste it to the https://developers.facebook.com/apps under the key hashes column.

Step 4

We need to take internet and Facebook provider permission in the manifest and :

Permission:

<uses-permission android:name="android.permission.INTERNET"/>

In place of APP_ID we need to add facebook app ID that was generated in https://developers.facebook.com/apps  

<provider android:authorities="com.facebook.app.FacebookContentProvider{APP_ID}"
          android:name="com.facebook.FacebookContentProvider"
          android:exported="true"/>

 

Step 5

After setting up Facebook integration we can send the Image. But to send the image we have to convert to Bitmap.

In Phimpme all the sharing function is established in Share Image Activity.    

   So, we need to convert the image to Bitmap:

BitmapFactory.Options bmOptions = new BitmapFactory.Options();
Bitmap image = BitmapFactory.decodeFile(saveFilePath, bmOptions);

saveFilePath is the path where the Edited Image is stored. BitmapFactory converts the file to Bitmap by using decodeFile() method.

Step 6

When share through Facebook button is pressed the image is converted to Bitmap and it is finally shared to the Facebook platform by using SharePhoto class:

SharePhoto photo = new SharePhoto.Builder()

       .setBitmap(image)

       .setCaption(sendMessage)

       .build();

SharePhotoContent content = new SharePhotoContent.Builder()

       .addPhoto(photo)

       .build();

ShareApi.share(content, null);

setCaption(): it sends text message with the image. In the case of Phimpme it gets the text message from the EditText stores to sendMessage.

The end result

When share through Facebook button is pressed, is checks if the user is already logged In or not. If the user is not logged In, the application will ask for Facebook ID and password.

After successfully logging In the application ask the permission to share the image.

Continue ReadingSharing Images on Facebook from Phimpme Android App
  • FOSSASIA
  • Blog
  • GitHub
  • Projects
  • Code of Conduct
  • About
  • Contact
Copyright - WordPress Theme by OceanWP
 

Loading Comments...
 

You must be logged in to post a comment.