How to catch errors in a javascript façade for firebase 3.0.2 when authenticating - scala.js

I'm trying to write a javascript façade in my scala-js code to leverage Google's Firebase authentication javascript framework. When authenticating to Firebase (after initializing), one will get either a Firebase User or an exception with a string error code describing the problem. Specifically, I'm trying to login using an email and password as described at https://firebase.google.com/docs/reference/js/firebase.auth.Auth#signInWithEmailAndPassword. Providing a correct email and password returns me a valid Firebase user which I've "façaded" like so:
#JSName("firebase.User")
#js.native
trait FirebaseUser extends FirebaseUserInfo {
var emailVerified : Boolean = js.native
var isAnonynous: Boolean = js.native
var providerData: js.Object = js.native
var refreshToken: String = js.native
}
object FirebaseUser {
def apply(emailVerified : Boolean, isAnonynous: Boolean, providerData: js.Object, refreshToken: String): FirebaseUser = {
js.Dynamic.literal(emailVerified = emailVerified, isAnonynous = isAnonynous, providerData = providerData, refreshToken = refreshToken).asInstanceOf[FirebaseUser]
}
}
And the Auth façade that contains the 'signInWithEmailAndPassword' method like so:
#JSName("firebase.auth.Auth")
#js.native
trait FirebaseAuth extends js.Object {
var app: FirebaseApp = js.native
var currentUser: FirebaseUser = js.native
def signInWithEmailAndPassword(email: String, password: String): Promise[FirebaseUser] = js.native
def signOut: Promise[Void] = js.native
def onAuthStateChanged(nextOrObserver: FirebaseUser => Unit, opt_error: FirebaseAuthError => Unit = null, opt_completed: Unit => Unit = null)
}
object FirebaseAuth {
def apply(app: FirebaseApp, currentUser: FirebaseUser): FirebaseAuth = {
js.Dynamic.literal(app = app, currentUser = currentUser).asInstanceOf[FirebaseAuth]
}
}
My code to invoke this looks like this:
// since 'signInWithEmailAndPassword()' returns promise, convert to future
val f1 = firebase.auth().signInWithEmailAndPassword(S.user.email, S.user.password).toFuture
f1 onComplete {
case Success(fbu) => {
fbuser = fbu
scope.modState(_.copy(loginState = isLoggedIn)).runNow()
}
case Failure(ex) => println("Error signing-in to firebase, error="+ex.getMessage)
case _ => println("Something else happened when signing-in...")
}
The success case works fine, but the failure case returns null when a String is expected that contains the reason for the error. What am I doing wrong? I suspect it has something to do with the fact that Firebase has its own Firebase.promise type and using the built-in scalajs scala.scalajs.js.Promise type is not enough--that I have to create a facade for the Firebase.Promise type.
I'm using sbt version 0.13.8 and scala-js plugin version 0.6.7

Related

How can i return the InsertedId from mongoDB document after insertion. Tried InsertedId but it returns null

Am using ktor and MongoDB as my backend for an android project. When inserting a document, the acknowledgment returns true, but when I get InsertedId, it returns null despite being inserted in the database.I need the inserted id so that I can store it in session and also return the inserted object with the id to android. Am new to MongoDB and could be doing something wrong.
Here is my POJO class in ktor
#Serializable
data class User(
#BsonId
val _id: String? = ObjectId.get().toString(),
val username: String,
val password: String,
val salt: String
)
Here is my repositoryImpl
class MongoUserDataSource(
db: CoroutineDatabase
): UserDataSource {
private val users = db.getCollection<User>()
override suspend fun getUserByUsername(username: String): User? {
return users.findOne(User::username eq username)
}
override suspend fun insertUser(user: User): BsonValue? {
return users.insertOne(user).insertedId
}
override suspend fun getUser(userId: String): User? {
return users.findOneById(userId)
}
}
When you do your findById, I believe you want to search using an ObjectId instead of the string value. I would update your insertUser function as so
override suspend fun insertUser(user: User): ObjectId? {
return users.insertOne(user).insertedId.asObjectId().value
}
and getUser like this
override suspend fun getUser(userId: ObjectId): User? {
return users.findOneById(userId)
}
Hope this helps!

How do I pass request.identity to the view

def edit(id: String) = SecuredAction(WithService("master")).async {implicit request =>
val futureEmp = collection.flatMap(_.find(Json.obj("_id" -> Json.obj("$oid" -> id))).cursor[Employee]().collect[List]())
futureEmp.map { emps: List[Employee] =>
implicit val message = messagesApi.preferred(request)
Ok(html.editForm(id, employeeForm.fill(emps.head)))
}.recover {
case t: TimeoutException =>
Logger.error("Problem found in employee edit process")
InternalServerError(t.getMessage)
}
}
Once you have wired up Silhouette in a play module, and injected your user model into the Environment trait:
trait YourCustomEnv extends Env {
type I = User // <- Whatever user model your app uses
type A = JWTAuthenticator
}
... you will be able to access the identity on a Secured endpoint by accessing the identity member:
def index() = silhouette.SecuredAction.async { implicit request =>
// The model of the authenticated user available here
val user: User = request.identity
Future.successful(Ok)
}
Assuming that you are using Twirl as the templating engine, you can pass this object to the view by adding it as a parameter to the template:
#(user: models.User)
... and calling the template like so from your controller:
def index() = silhouette.SecuredAction.async { implicit request =>
val user: User = request.identity
Future.successful(Ok(views.html.home(user))))
}

Silhouette authorization using request data

I use Silhouette and Play 2.4 and I'd like to restrict actions if a SecuredRequest body contains something wrong.
I know, I should use trait Authorization as described by official docs.
I'm trying to do the following:
case class WithCheck(checkCriteria: String) extends Authorization[User, CookieAuthenticator] {
def isAuthorized[B](user: User, authenticator: CookieAuthenticator)(implicit request: Request[B], messages: Messages) = {
Future.successful(user.criteria == checkCriteria)
}
}
and than
def myAction = SecuredAction(WithCheck("bar")) { implicit request =>
val foo = ...// deserialize object from request.body
val checkCriteria = foo.criteria
// do something else here
}
How can I use the checkCriteria value in the class WithCheck?
I found a solution.
Somehow, I was blind to see that isAuthorized has the same request as an implicit parameter. So, the check could be done entirely into the isAuthorized. For example,
case class WithCheck() extends Authorization[User, CookieAuthenticator] {
def isAuthorized[B](user: User, authenticator: CookieAuthenticator)(implicit request: Request[B], messages: Messages) = {
val foo = upickle.read[Foo](request.body.toString())
Future.successful(user.criteria == foo.criteria)
}
}

Is there a way to tell all methods inside a class to do function call without writing those function calls to every method

I'm coding request calls to tens of services which should be authorized.
I noticed I have written a lot of copy&paste code to the beginning of all methods inside service classes because they all must be authorized before using any services.
Little example...
class AuthorizationService {
val authorized = List("James", "007")
def authorize(user: String) = {
if (!authorized.contains(user)) throw new RuntimeException(s"User '$user' not authorized")
}
}
class Service1 {
val authorizationService = new AuthorizationService
def doThis(user: String) = {
authorizationService.authorize(user)
println(s"User '$user' did this")
}
def doThat(user: String) = {
authorizationService.authorize(user)
println(s"User '$user' did that")
}
}
Now imagine there are 30 service classes with three methods each and I continue to do authorization like the way I have I end up writing 90 functions calls.
Something like this maybe ... It still requires your service to change, but not as much:
object AuthToken {
implicit def auth(s: String)(implicit service: AuthService) = {
service.authorize(s)
AuthToken(s)
}
}
case class AuthToken private[AuthToken] (s: String) {
override def toString = s;
}
class Service1 {
implicit val authorizationService = new AuthorizationService
def doThis(user: AuthToken) = {
println(s"User '$user' did this")
}
}
Now, if you do new Service1().doThis("James"), it will implicitly call your auth service first to convert the name into token.
You could use it like this:
object Tester {
class AuthorizationService {
val authorized = List("James", "007")
def authorize(user: String) = {
if (!authorized.contains(user)) throw new RuntimeException(s"User '$user' not authorized")
}
}
def authorize(businessLogic: => Unit)(implicit
authorizationService: AuthorizationService,
user: String): Unit = {
// authorization logic
authorizationService.authorize(user)
println(s"User '$user' did this")
// actual code that needs to be executed
businessLogic
}
class Service1(implicit val authorizationService: AuthorizationService) {
def doThis(implicit user: String) = authorize {
println("doThis()")
}
def doThat(implicit user: String) = authorize {
println("doThat()")
}
}
def main(args: Array[String]) {
implicit val authorizationService = new AuthorizationService
val s = new Service1()
s.doThat("James")
s.doThat("007")
s.doThat("Neo")
}
}
you could use a crude composition pattern:
class ServiceAuthorizationExecutor {
def call(user: String, delegate: DELGATE_TYPE) = {
authorizationService.authorize(user)
delegate()
}
}
This is a classic AOP problem. The last time I looked at AOP was 12 years ago though, so I'm not sure what the state of it all is.

type mismatch; found : Int required: String when trying to persist the form data in play framework

I have a model as follows:
case class User(username: String, email: String) {
var id:Int = User.nextId
}
object User {
protected var currentId = 0
def nextId: Int = {
currentId += 1
currentId
}
}
And my Controller looks like this:
object Users extends Controller {
val users: scala.collection.mutable.Map[String, User] = new HashMap
val form = Form(
mapping(
"username" -> text,
"email" -> text
)(User.apply)(User.unapply))
def add = Action {
Ok(views.html.users.add(form))
}
def save = Action{
implicit request =>
val user = form.bindFromRequest.get
users.put(user.id, user)
Ok("contact saved")
}
}
But when I compile the code my browser throws an error telling there is a miss match in the type that is accepted by the users.put(user.id, user).
The error message looks as follows:
When I change the type of the id as string then it will work but I want to keep my id as integer and not string.
Is there any way I can achieve this. I am using play framework 2.11.1.
What is that I am missing. Any help would be greatly appreciated since I am new to play framework.
users is a map from String to User.
val users: scala.collection.mutable.Map[String, User] = new HashMap
The put method expects a key of type String and a value of type User, but you tried to use it with a key of type Int.
You need to change your map to the type
scala.collection.mutable.Map[Int, User]
or instead you could use a value of type String as key.