Is there a better way to catch javascript errors in clojurescript? - error-handling

I've been working with firebase in clojurescript and I've attempted the advice here:
How to catch any Javascript exception in Clojurescript?
The code I have so far is:
(defn register [email password]
(try
(let [reg (.createUserWithEmailAndPassword (.auth firebase) email password)
_ (.log js/console reg)]
reg)
(catch :default e
(.log js/console "Register Error:" e))))
As I suspected the reason it's not been caught is that the evaluation could have been occurring later and this was to test the idea.
I have also tried:
(defn register [email password]
(try
(.createUserWithEmailAndPassword (.auth firebase) email password)
(catch :default e
(.log js/console "Register Error:" e))))
I call this using:
(apply register ((juxt :email :password) #app-state))
If I pass it an email I've already registered with I get as expected an auth/email-already-in-use error, but I can't catch it.
www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=AIzaSyDzsfz98Y6Pjl1n-uAzfI6GHWKqShFdRI4:1
POST https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=AIzaSyDzsfz98Y6Pjl1n-uAzfI6GHWKqShFdRI4 400 ()
firebase.inc.js:81
Uncaught
Qcode: "auth/email-already-in-use"
message: "The email address is already in use by another account."
__proto__: Error
(anonymous) # firebase.inc.js:81
How do I catch it? Or is the only way of handling this by using the raw javascript?
firebase.auth().createUserWithEmailAndPassword(email, password).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});

Firebase auth is asynchronous. Javascript's (and, generally, Clojurescript's) try...catch does not work in callbacks. Call the catch function provided by the Firebase handler with your callback on error, like this - this is the literal translation of the JS code in your post above:
(defn register [email password]
(.. firebase auth (createUserWithEmailAndPassword email password)
(catch (fn [e] (.log js/console "Register Error:" e))))

Related

Post Confirmation ConfirmForgotPassword lambda execution returns InvalidLambdaResponseException - Unrecognizable lambda output

I have spent a bunch of hours to solve this issue, all related SO answers seem to be outdated or irrelevant.
State:
Amplify.js "^4.3.10" with code
Auth.forgotPasswordSubmit(email, confirmationCode, password)
.then(_ => this.notification.success("Confirmation OK"))
.catch(err => console.log(err));
Lambda on Node.js 14
Cognito trigger "Post confirmation"
Lambda function code:
'use strict';
exports.handler = async (event, context, callback) => {
if (event.triggerSource === "PostConfirmation_ConfirmForgotPassword") {
const postConfirmEmail = () => `<html><body>HERE IS MY TEMPLATE</body></html>`;
event.response = {
emailSubject: "Reset Password Notification",
emailMessage: postConfirmEmail()
};
callback(null, event);
}
};
As result, I am getting
InvalidLambdaResponseException: Unrecognizable lambda output (Error 400)
The thing is that password is really updating as expected, but e-mail confirmation is NOT sent and error remains.
TIP: User is CONFIRMED. Tried also with "context.done(null, event);" / "return event;" but response is always with the same error.
You shouldn't be using an async handler with the callback. It's either one or the other.
Simply return event without calling the callback or don't make your function async.
Additionally, Cognito will not send confirmation emails, you will have to implement this functionality yourself.

Error 403 when get request to server. Server contains core header

I'm running a server with clojure on localhost:3000. The server talks to the client, which is a react native app that's using axios to talk to the server. However the communication with the server is returning a 403 error.
Call to the server:
export const invest = (itemid, amount) => async dispatch => {
console.log("investing in actions")
const domain = 'localhost:3000'
const res = axios.post(domain + '/api/invest', {itemid: itemid, amount: amount});
console.log("response is", res)
dispatch({ type: INVESTED, payload:res.data});
}
Server contains a reitit route called "/api/invest", and this route will call a function called featured/invest. But instead I'm getting a 403 error in the client:
(ns humboiserver.routes.home
(:require
[humboiserver.layout :as layout]
[clojure.java.io :as io]
[humboiserver.middleware :as middleware]
[ring.util.response]
[ring.util.http-response :as response]
[humboiserver.routes.featured :as featured]))
(defn home-page [request]
(layout/render request "home.html" {:docs (-> "docs/docs.md" io/resource slurp)}))
(defn about-page [request]
(layout/render request "about.html"))
(defn home-routes []
[""
{:middleware [middleware/wrap-csrf
middleware/wrap-formats]}
["/" {:get home-page}]
["/api"
["/about" {:get about-page}]
["/featured" featured/get-featured]
["/invest" featured/invest]
]
])
Even the invested prn statement isn't printed in the logs.
;; featured/invest function.
(defn response [data & [status]]
{:status (or status 200)
:headers {"Content-Type" "application/json"
"Access-Control-Allow-Headers" "Content-Type"
"Access-Control-Request-Method" "GET, OPTIONS"
"Access-Control-Allow-Origin" "*"
"Access-Control-Allow-Credentials" true
}
:body (pr-str data)})
(defn invest [req]
(prn "invested")
(response (db/find "featured" {})))
403 error:
[Warning] Possible Unhandled Promise Rejection (id: 0): (AppEntry.bundle, line 42288)
Error: Request failed with status code 403
createError#http://127.0.0.1:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&minify=false:156390:26
settle#http://127.0.0.1:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&minify=false:156380:25
handleLoad#http://127.0.0.1:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&minify=false:156280:15
dispatchEvent#http://127.0.0.1:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&minify=false:32753:31
setReadyState#http://127.0.0.1:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&minify=false:31822:27
__didCompleteResponse#http://127.0.0.1:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&minify=false:31653:29
emit#http://127.0.0.1:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&minify=false:7566:42
__callFunction#http://127.0.0.1:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&minify=false:3195:36
http://127.0.0.1:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&minify=false:2927:31
__guard#http://127.0.0.1:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&minify=false:3149:15
callFunctionReturnFlushedQueue#http://127.0.0.1:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&minify=false:2926:21
callFunctionReturnFlushedQueue#[native code]
http://localhost:19000/debugger-ui/debuggerWorker.aca173c4.js:4:907
How to fix this error?
Hi I think you need to send an Anti-forgery token if I'm not mistaken...
https://github.com/ring-clojure/ring-anti-forgery
You can use curl to test accessing your server via the command line

How to add Friend auth to Chestnut template

I've struggled for a few days trying to get a simple use of the security library, Friend, to work with the Chestnut clj/cljs template.
A POST request to the the /login uri is supposed log me in and allow access the protected routes like /role-user. But for some reason I am not able to login, the POST returns a 303 and routes me back to the root page.
I added the Friend middleware inside the http-handler function. Is this the correct place to apply this sort of middleware? I thought maybe the reload or api-defaults middleware could be messing up friend middleware? However, removing them does not fix things.
(def http-handler
(if is-dev?
(-> #'routes
(reload/wrap-reload)
(friend/authenticate
{:allow-anon? true
:login-uri "/login"
:default-landing-uri "/"
:unauthorized-handler #(-> (h/html5 [:h2 "You do not have sufficient privileges to access " (:uri %)])
resp/response
(resp/status 401))
:credential-fn (fn [x]
(let [res (creds/bcrypt-credential-fn #users x)]
(log/info x)
(log/info res)
res))
:workflows [(workflows/interactive-form)]})
(wrap-defaults api-defaults))
(wrap-defaults routes api-defaults)))
Based on the print statements I was able to figure out that the credential-fn function does get called on the POST request, with the correct params, and the function returns the correct (authenticated) result.
This http-handler is used as such
(defn run-web-server [& [port]]
(let [port (Integer. (or port (env :port) 10555))]
(print "Starting web server on port" port ".\n")
(run-jetty http-handler {:port port :join? false})))
(defn run-auto-reload [& [port]]
(auto-reload *ns*)
(start-figwheel))
(defn run [& [port]]
(when is-dev?
(run-auto-reload))
(run-web-server port))
For what it's worth, here are my routes.
(defroutes routes
(GET "/" req
(h/html5
misc/pretty-head
(misc/pretty-body
(misc/github-link req)
[:h3 "Current Status " [:small "(this will change when you log in/out)"]]
[:p (if-let [identity (friend/identity req)]
(apply str "Logged in, with these roles: "
(-> identity friend/current-authentication :roles))
"anonymous user")]
login-form
[:h3 "Authorization demos"]
[:ul
[:li (e/link-to (misc/context-uri req "role-user") "Requires the `user` role")]]
[:p (e/link-to (misc/context-uri req "logout") "Click here to log out") "."])))
(GET "/login" req
(h/html5 misc/pretty-head (misc/pretty-body login-form)))
(GET "/logout" req
(friend/logout* (resp/redirect (str (:context req) "/"))))
(GET "/role-user" req
(friend/authorize #{::users/user} "You're a user!")))
I figured it out. (wrap api-defaults) does not allow sessions and Friend is trying to use them. I should be using site-defaults instead. See ring middleware for more info.

Calling Objective c method in swift app

Okay I've got the bridging Header all set up and I can now use my objective c code but I'm having a hard time understanding how to use objective c methods in swift.
This is the method in my .m file that I imported
-(void)sendWithLoadMessage:(NSString *)loadMessage
successMessage:(NSString *)successMessage
failureMessage:(NSString *)failureMessage
recoveryOptions:(NSString *)recoveryOptions
success:(void (^)(CustomResponse *response))success
failure:(void (^)(CustomResponse *response))failure
and here is how I use it in my objective c app. I need to know how to do this in swift:
CustomRequest *request = [_user login];
[request sendWithLoadMessage:#"Signing In"
successMessage:#"Signed In"
failureMessage:#"Failed to log in"
recoveryOptions:#"try again"
success:^(CustomResponse *response) {
....
}
To use an Objective C Method in swift, you need to treat the method like a Swift function. You call functions on an instance through .
For you, it would be like this:
let request = _user.login
request.sendWithLoadMessage("Signing In", successMessage: "Signed In", failureMessage: "Failed to log in", recoveryOptions: "try again", response: { CustomResponse in
println(response)
})
Taking advantage of trailing closures here:
let request = _user.login
request.sendWithLoadMessage("Signing In", successMessage: "Signed In", failureMessage: "Failed to log in", recoveryOptions: "try again") { response: CustomResponse in
println(response)
}
Using the $ syntax, you can make this even shorter by doing it this way. If you already know the parameters passed back in the block, you can access the list of parameters without typing it out by calling $indexOfParameter. The $ syntax is 0 indexed so your first parameter would be $0, your second parameter would be $1, etc.
let request = _user.login
request.sendWithLoadMessage("Signing In", successMessage: "Signed In", failureMessage: "Failed to log in", recoveryOptions: "try again") {
println($0)
}

Authenticating the cobrand

I created a new developer account and I am having a problem authenticating with the REST API.
POST https://rest.developer.yodlee.com/services/srest/restserver/v1.0/authenticate/coblogin
{ cobrandLogin: 'sbCob*****',
cobrandPassword: '**********' }
the system responds with:
{ Error: [ { errorDetail: 'Internal Core Error has occurred' } ] }
am I doing something wrong?
I am testing the API with Postman and apparently I need to send the params with x-www-form-urlencoded to make it work. Using the default form-data lead to the above mentioned error.
In my case, this was solved by changing the content-type as per http://developer.yodlee.com/Aggregation_API/Aggregation_Services_Guide/Aggregation_REST_API_Reference
require 'rest-client'
module Yodlee
def self.login_to_yodlee
site = self.site_resource
login_hash = {
cobrandLogin: 'yourlogin',
cobrandPassword: 'yourpassword'
}
begin
response = site["/authenticate/coblogin"].post login_hash, :'content-type' => 'application/x-www-form-urlencoded'
puts response
rescue RestClient::ResourceNotFound => ex
raise Exception.new(ex.response)
rescue Exception => ex
raise Exception.new(ex)
end
end
def self.site_resource
RestClient::Resource.new('https://rest.developer.yodlee.com/services/srest/restserver/v1.0')
end
end
Yodlee.login_to_yodlee
Generally, this error comes when you do not provide the input parameter's name correctly; while in this mentioned code above I could see that both of them are correct. I'd suggest you to please double check the input parameter name(case sensitive) as well properly. And just to mention you should be sending it as two different parameters i.e., 'cobrandLogin' and cobrandPassword.