My web app on Yesod, Auth-HashDB, and PostgreSQL refuses to compile -- Couldn't match type ‘AuthEntity App’ with ‘User’ - postgresql

I've been trying to give myself a crash course in Yesod, but I can't seem to figure out what I'm doing wrong here. It's likely a conceptual failing, but I've more-or-less copy-pasted the code available on various short introductions to HashDB in an attempt to make a hashed DB authentication system, but no dice.
Foundation.hs:136:23:
Couldn't match type ‘AuthEntity App’ with ‘User’
In the expression: getAuthIdHashDB AuthR (Just . UniqueUser) creds
In an equation for ‘getAuthId’:
getAuthId creds = getAuthIdHashDB AuthR (Just . UniqueUser) creds
In the instance declaration for ‘YesodAuth App’
From each segment of code that's relevant:
config/models:
User
name Text
password Text Maybe
UniqueUser name
Model.hs:
import Yesod.Auth.HashDB (HashDBUser, userPasswordHash, setPasswordHash)
import Database.Persist.Quasi (lowerCaseSettings)
...
share [mkPersist sqlSettings, mkMigrate "migrateAll"]
$(persistFileWith lowerCaseSettings "config/models")
instance HashDBUser User where
userPasswordHash = userPassword
setPasswordHash h u = u { userPassword = Just h }
Foundations.hs:
...
import Yesod.Auth
import Yesod.Auth.HashDB (authHashDBWithForm, getAuthIdHashDB, authHashDB)
import Yesod.Auth.Message (AuthMessage (InvalidLogin))
...
instance YesodAuth App where
type AuthId App = UserId
loginDest _ = HomeR
logoutDest _ = HomeR
redirectToReferer _ = True
authPlugins _ = [ authHashDB (Just . UniqueUser) ]
getAuthId creds = getAuthIdHashDB AuthR (Just . UniqueUser) creds
authHttpManager = getHttpManager
Any help would be appreciated. I still kind of suck at Haskell, so this is also my attempt at a crash course in it as well.

This typically means that you don't have an AuthEntity associated type declared, which in turn means that you don't have a YesodAuthPersist instance. In your case, this is probably just:
instance YesodAuthPersist App where
type AuthEntity App = User
This is provided by the Yesod scaffolding.

Related

Can't get CoffeeScript to recognize a function in a js file

I am writing a simple app in Coffeescript to control a Philips Hue light. I have included this module into my project. The below code seems to work fine up until I try to set the color of the lights using setLightState. The compiler says the function isn't a function. I don't quite understand why it doesn't recognize the function.
# Connect with Philips Hue bridge
jsHue = require 'jshue'
hue = jsHue()
# Get the IP address of any bridges on the network
hueBridgeIPAddress = hue.discover().then((bridges) =>
if bridges.length is 0
console.log 'No bridges found. :('
else
(b.internalipaddress for b in bridges)
).catch((e) => console.log 'Error finding bridges', e)
if hueBridgeIPAddress.length isnt 0 # if there is at least 1 bridge
bridge = hue.bridge(hueBridgeIPAddress[0]) #get the first bridge in the list
# Create a user on that bridge (may need to press the reset button on the bridge before starting the tech buck)
user = bridge.createUser('myApp#testdevice').then((data) =>
username = data[0].success.username
console.log 'New username:', username
bridge.user(username)
)
if user?
#assuming a user was sucessfully created set the lighting to white
user.setLightState(1, {on:true, sat:0, bri:100, hue:65280}).then((data) =>
# process response data, do other things
)
As you can see on the github page of the jshue lib, bridge.createUser does not directly return a user object.
Instead the example code sets the user variable inside the then function of the returned promise:
bridge.createUser('myApp#testdevice').then(data => {
// extract bridge-generated username from returned data
var username = data[0].success.username;
// instantiate user object with username
var user = bridge.user(username);
user.setLightState( .... )
});
It can be expected that - using this approach - the user variable will be set correctly and user.setLightState will be defined.
A self-contained example:
Take this Codepen for example:
url = "https://api.ipify.org?format=json"
outside = axios.get(url).then (response) =>
inside = response.data.ip
console.log "inside: #{inside}"
inside
console.log "outside: #{outside}"
The console output is
outside: [object Promise]
inside: 178.19.212.102
You can see that:
the outside log is first and is a Promise object
the inside log comes last and contains the actual object from the Ajax call (in this case your IP)
the then function implicitly returning inside does not change anything

How to Pass Original PBKDF2 Hash from SQLite3 DB

I know that there are a lot of questions on PBKDF2 and hashes, but most of them seem to talk about bits. Perhaps that is what I need to learn more about, but I'm hoping there is something more straight-forward for my problem.
Note: These are two separate programs (so the variables will seem to repeat, but do not).
The first creates a hashed password and stores it in the db ... This is working fine.
from pbkdf2 import crypt
import sqlite3
cemail = input("Email: ")
cpassword = input("Password: ")
pwhash = crypt(cpassword)
connection = sqlite3.connect('/Users/Air/Desktop/users.db')
cursor_v = connection.cursor()
cursor_v.execute("insert into user (cemail, cpassword) values (?,?)", (cemail, pwhash))
connection.commit()
cursor_v.close()
The problem is here, where I go to check the database for the original hashed password. Once the hashed password went into the database from the first program, is that it? Is it gone forever (i.e. not able to be compared to something else later, like another password during login)?
cemail = input("Login with Email: ")
cpassword = input("Login with Password: ")
pwhash = crypt(cpassword)
connection = sqlite3.connect('/Users/Air/Desktop/users.db')
cursor_v = connection.cursor()
cursor_v.execute("SELECT * FROM user WHERE cemail=? AND cpassword=?", (cemail,pwhash))
row = cursor_v.fetchone()
if pwhash == crypt(pwhash, cpassword):
print("Welcome")
else:
print("Invalid")
Any help or guidance is appreciated.

Flask-MongoKit find_one()

I'm trying to use Flask-MongoKit as follows (with both attempts to find_one failing):
app = Flask('app-name')
db = MongoKit(app)
db.register([database.Users])
with app.app_context():
print db['users'].find_one()
print db.Users.find_one()
When I used plain MongoKit (non-Flask version), and this worked (as follows)
db = Connection()
db.register([database.Users])
print db.Users.find_one()
Thanks!
EDIT:
The database and collection are defined as follows.
class Users(Document):
__collection__ = 'users'
__database__ = 'database'
Flask-MongoKit doesn't use MongoKit's __database__ value. Instead, it uses an application config setting named MONGODB_DATABASE. If that isn't set, it defaults to a database named flask. If you change your code to
app = Flask('app-name')
app.config['MONGODB_DATABASE'] = 'database'
db = MongoKit(app)
your calls to find_one() should work.
The relative bits can be found here and here.

how to build a REST hierarchy using spyne

I am trying to build a REST web service using spyne. So far I have been able to use ComplexModel to represent my resources. Something very basic, like this (borrowed from the examples):
class Meta(ComplexModel):
version = Unicode
description = Unicode
class ExampleService(ServiceBase):
#srpc(_returns=Meta)
def get_meta():
m = Meta()
m.version="2.0"
m.description="Meta complex class example"
return m
application = Application([ExampleService],
tns='sur.factory.webservices',
in_protocol=HttpRpc(validator='soft'),
out_protocol=JsonDocument()
)
if __name__ == '__main__':
wsgi_app = WsgiApplication(application)
server = make_server('0.0.0.0', 8000, wsgi_app)
server.serve_forever()
To run I use curl -v "http://example.com:8000/get_meta" and I get what I expect.
But what if I would like to access some hierarchy of resources like http://example.com:8000/resourceA/get_meta ??
Thanks for your time!
Two options: Static and dynamic. Here's the static one:
from spyne.util.wsgi_wrapper import WsgiMounter
app1 = Application([SomeService, ...
app2 = Application([SomeOtherService, ...
wsgi_app = WsgiMounter({
'resourceA': app1,
'resourceB': app2,
})
This works today. Note that you can stack WsgiMounter's.
As for the dynamic one, you should use HttpPattern(). I consider this still experimental as I don't like the implementation, but this works with 2.10.x, werkzeug, pyparsing<2 and WsgiApplication:
class ExampleService(ServiceBase):
#rpc(Unicode, _returns=Meta, _patterns=[HttpPattern("/<resource>/get_meta")])
def get_meta(ctx, resource):
m = Meta()
m.version = "2.0"
m.description="Meta complex class example with resource %s" % resource
return m
Don't forget to turn on validation and put some restrictions on the resource type to prevent DoS attacks and throwing TypeErrors and whatnot. I'd do:
ResourceType = Unicode(24, min_len=3, nullable=False,
pattern="[a-zA-Z0-9]+", type_name="ResourceType")
Note that you can also match http verbs with HttpPattern. e.g.
HttpPattern("/<resource>/get_meta", verb='GET')
or
HttpPattern("/<resource>/get_meta", verb='(PUT|PATCH)')
Don't use host matching, as of 2.10, it's broken.
Also, as this bit of Spyne is marked as experimental, its api can change any time.
I hope this helps

Erlang variable pattern matching

I have a service_echo function in a simple chat application which uses SockJS for implementing multi-user private chat. I created an ETS table for the list of online users. By storing SockJS session, I thought to send message to that Connection whenever I receive a message from a different Connection.
Here is my service_echo code.
service_echo(Conn, {recv, Data}, state) ->
Obj = mochijson2:decode(Data),
{struct, JsonData} = Obj,
Name = proplists:get_value(<<"name">>, JsonData),
A = ets:lookup(username,Name),
io:format("~p",[Conn]),
if
length(A) =:= 0 ->
ets:insert(username,{Name,Conn});
true ->
[{AA,BB}] = ets:lookup(username,Name),
BB:send(Data)
end,
io:format("hello");
Even though Conn and BB are same, still Conn:send(data) sends a valid data to the browser while BB:send(Data) does nothing and even does not show an error.
Since I'm a new to Erlang, please excuse me for any unintented mistakes.
First of all, let me advise you on never using length(A) =:= 0 for testing whether the list A is empty or not; if A a long list, counting its elements will cost you a lot, although the result will not actually be used. Use A =:= [] instead, simpler and better.
I don't understand why you're saying that Conn and BB are the same. This does not follow from the code that you have posted here. If Name is not in the table, you insert an entry {Name, Conn}. Otherwise, if Name exists in the table and is related to a single object BB, you assume that this BB is a module and you call the send function defined therein.
It could be that you're reading wrong the semantics of if --- if that's the case, don't let the true guard confuse you, this is how an if-then-else is written in Erlang. Maybe you wanted to have something like:
...
A = ets:lookup(username,Name),
if
A =:= [] ->
ets:insert(username,{Name,Conn})
end,
[{_,BB}] = ets:lookup(username,Name),
BB:send(Data)
...
or even better:
...
A = ets:lookup(T,Name),
if
A =:= [] ->
ets:insert(T,{Name,Conn}),
BB = Conn;
true ->
[{_,BB}] = A
end,
BB:send(Data)
...
On the other hand, it could be that I misunderstood what you're trying to do. If that's the case, please clarify.