sqlalchemy query issue - sqlalchemy

I have a user update function and I allow users to change their email address but the same address must be unique in the database so, before I update, I must check if their new email already exists in the database but the query I use to check that returns the same row. Example:
user = User.query.get(1)
user.email = 'some#email.com'
if user.validate(): # The validate function performs a query to see if 'some#email.com' is already taken
user.save()
Now going into the validate function I have:
check = User.query.filter_by(User.email='some#email.com').first()
if check:
# email already exists
Problem is that check holds the same user I'm editing. Sqlalchemy submits the update to the database but under some sort of transaction so my query returns the same user I'm editing. I've solved this by creating a second session object but seems like an overkill. Any better ideas? Am I making sense?

Why not check, whether a user with a given e-mail address exists, before manipulating an existing user? You could e.g. write a standalone function for that:
def user_email_exists(email):
return (not User.query.filter(User.email=email) == None)
Then call user_email_exists before the attempt to change the user object.
...
# User object to alter
user = ...
# the new email address, which needs to be checked
new_email_addr = 'new#shiny.com'
if user_email_exists(new_email_addr):
raise SomeMeaningfulException() # or some `flash` message + a redirect
else:
user.email = new_email_addr
db.session.add(user)
db.commit()
...

The simplest way is probably just to add a second filter to the query inside your validate function. Instead of having it select any user with that email address, have it select any user with that email address and NOT the same username or user id. That way you're ensuring to only get a return if there is a different user with that email address.

Related

Node js - how can i do error handling when using mysql2?

i want to handle the probable errors of mysql db. in my case, i have users table that has 7 columns. column email and username values should be unique and i set that for them. but in my sign up form, when users enter and submit their account infos, their entered username and email can be in the database. so in this case, mysql throws an error. for example in my database there is a row with test#test.com email and saman138 username. if a user enters test#test.com for email and saman138 for username, mysql throws an error like this:
Duplicate entry 'saman138' for key 'users.username_UNIQUE'
But the main problem is that i cant display the right error to user. I actually dont know how to do that in the best with the highest performance. For example how can i recognize that the users entered password is duplicated in the database and display the right error to user? I can send two extra queries to get the row that has the entered email or password and then send an error with this message:
your entered username and email already exists in database. Please
enter an other email and username.
this is my codes to insert users infos in to the users table:
import bcrypt from "bcrypt";
import { SignUpInfos } from "../interfaces/Interfaces";
import { mysql } from "../utils/DB";
const signUpUser = async (datas: SignUpInfos) => {
const hashedPassword = await bcrypt.hash(datas["user-password"], 10);
const results = await new Promise((resolve, reject) => {
mysql.query(
"INSERT INTO users ( fullname, email, username, password ) VALUES ( ?, ?, ?, ? )",
[
datas["user-fullname"],
datas["user-email"],
datas["user-username"],
hashedPassword,
],
(err, result) => {
if (err) reject(err);
else resolve(result);
}
);
});
return results;
};
export { signUpUser };
so what is the best way to return the right error message if there was an error? is there any best way to do that or i should send to extra queries? thanks for help :)
As according to the MVC pattern, input validation is typically done before the request gets to the database (in your javascript code), not relying on database errors to inform you that something is wrong.
For example:
First you might check that a username is a valid username through business rules in the javascript; checking that the username doesnt have spaces or something.
Then you might search the database to see if there are any users with a given name, return the number and then use that to tell the user that a name is already taken. Only once this search returns that there are no other similar usernames in the database should you actually let them submit the new account.
But, that is not to say you should abandon the database rules altogether because they are important to ensuring someone doesnt do something dodgy like mess with your database (as an extreme) by bypassing the javascript code somehow and adding duplicate accounts -- that would be tragic.
Where does input validation belong in an MVC application?
"with the highest performance" -- "premature optimization". The login process, even when accounting for error cases, takes only milliseconds. There is no need to optimize this.
Also, since the usual case is "no errors" it is best to assume there will be no errors, then let some lower-level process (such as the databse INSERT) catch the error. If, instead, you checked for errors first, you would usually be wasting your time.
Anyway, the test and the insert must be done atomically, or else someone else can sneak in between your test and your insert and, say, grab the user_name. That is, the two must be combined into an "atomic" action. And the db, with UNIQUE constraints, does that nicely for you.

Anyway to get dkims records for verifying ses domain in boto?

Tinkering around with verifying a couple of domains and found the manual process rather tedius. My DNS controller offers API access so I figured why not script the whole thing.
Trick is I can't figure out how to access the required TXT & CNAME records for DKIMS verification from boto, when I punch in
dkims = conn.verify_domain_dkim('DOMAIN.COM')
it adds DOMAIN.COM to the list of domains pending verification but doesn't provide the needed records, the returned value of dkims is
{'VerifyDomainDkimResponse': {
'ResponseMetadata': {'RequestId': 'REQUEST_ID_STRING'},
'VerifyDomainDkimResult': {'DkimTokens': {
'member': 'DKIMS_TOKEN_STRING'}}}}
Is there some undocumented way to take the REQUEST_ID or TOKEN_STRING to pull up these records?
UPDATE
If you have an aws account you can see the records I'm after at
https://console.aws.amazon.com/ses/home?region=us-west-2#verified-senders:domain
tab: Details:: Record Type: TXT (Text)
tab: DKIM:: DNS Record 1, 2, 3
these are the records required to add to the DNS controller to validate & allow DKIM signatures to take place
This is how I do it with python.
DOMINIO = 'mydomain.com'
from boto3 import Session
session = Session(
aws_access_key_id=MY_AWS_ACCESS_KEY_ID,
aws_secret_access_key=MY_AWS_SECRET_ACCESS_KEY,
region_name=MY_AWS_REGION_NAME)
client = session.client('ses')
# gets VerificationToken for the domain, that will be used to add a TXT record to the DNS
result = client.verify_domain_identity(Domain=DOMINIO)
txt = result.get('VerificationToken')
# gets DKIM tokens that will be used to add 3 CNAME records
result = client.verify_domain_dkim(Domain=DOMINIO)
dkim_tokens = result.get('DkimTokens') # this is a list
At the end of the code, you will have "txt" and "dkim_tokens" variables, a string and a list respectively.
You will need to add a TXT record to your dns, where the host name is "_amazonses" and the value is the value of "txt" variable.
Also you will need to add 3 CNAME records to your dns, one for each token present in "dkim_tokens" list, where the host name of each record is of the form of [dkimtoken]._domainkey and the target is [dkimtoken].dkim.amazonses.com
After adding the dns records, after some minutes (maybe a couple of hours), Amazon will detect and verify the domain, and will send you an email notification. After that, you can enable Dkim signature by doing this call:
client.set_identity_dkim_enabled(Identity=DOMINIO, DkimEnabled=True)
The methods used here are verify_domain_identity, verify_domain_dkim and set_identity_dkim_enabled.
You may also want to take a look a get_identity_verification_attributes and get_identity_dkim_attributes.
I think the get_identity_dkim_attributes method will return the information you are looking for. You pass in the domain name(s) you are interested in and it returns the status for that identity as well as the DKIM tokens.

MySQL Query - Check if data row contains a user_id

I have a sessions table and what I am trying to do is run a query to check if a certain account is logged in.
My query looks like this:
SELECT id FROM sessions WHERE data LIKE '%4%'
But with a query like that, if the user_id of "14" is logged in, that query will return True. How do I check to see if a certain number exists and matches exactly?
Include the delimiters in your search:
WHERE data LIKE '%:4;%'
why don't you add another field for user_id to the session table?
EXAMPLE:
I have a site where a user can only be logged in from one location at a time. If they try and log in from another location (IE start a new session) then i kill all of their previous logins.
So as part of my login script:
// log this user out of any other active sessions
$sql = sprintf("DELETE
FROM sessions
WHERE id_user=%s",
mysql_real_escape_string($_SESSION['id_user'])
);
// Associate this session with this user
$sql = sprintf("UPDATE sessions
SET id_user=%s
WHERE id=%s",
mysql_real_escape_string($_SESSION['id_user']),
session_id()
);
and so i can have id_user as an additional field in my session FKed to my user table... its a little more normalized and lets you do quick "Who is currently using this site" queries without too much parsing and fuss.

Multiple individual users on one database

I have a .sql database with which i interact using Django .
The database in the beginning is filled with public data that can be accessed from anynone.
Multiple individual users can add rows into a table(private data).
How can a user see only the changes he made in the database(private data)?
I assume you're using django.contrib.auth. You just need to do something like:
from django.contrib.auth.models import User
# ...
class PrivateData(models.Model):
# ... private data fields ...
user = models.ForeignKey(User)
Then you can get just that user's fields with:
PrivateData.objects.filter(user=request.user)
EDIT: So, if your users are just IP addresses, and you're not using a login mechanism, you don't really need django.contrib.auth... though it's good to have anyway since you can use it to authenticate yourself and use the built-in admin stuff to manage your site.
If you just want to tie data to IP addresses, set up an IPUser model:
class IPUser(models.Model):
address = models.CharField(max_length=64, unique=True) # Big enough for IPv6
# Add whatever other discrete (not list) data you want to store with this address.
class PrivateData(models.Model):
# ... private data fields ...
user = models.ForeignKey(IPUser)
The view function looks something like:
def the_view(request):
remoteAddr = request.META['REMOTE_ADDR']
try:
theUser = IPUser.objects.get(address=remoteAddr)
except IPUser.DoesNotExist:
theUser = IPUser.objects.create(address=remoteAddr)
userModifiedData = PrivateData.objects.filter(user=theUser)
One thing to note: when you're testing this with manage.py runserver, you'll need to specify the IP address via environment variable:
$ REMOTE_ADDR=127.0.0.1 manage.py runserver
When you use Django with a real web server like Apache, the server will set the variable for you.
There are probably several ways to optimize this, but this should get you started.
I'm assuming that users have to log into this application. If yes, add a column to every table for the username. Add WHERE username = ? to every query so they can see only their data.
For data manipulation requests, make sure that the username matches the value for every row; forbid the operation if not true.

Auto username suggestion

I want an auto username suggestion if a username is already used ,using mysql procedure
By User Name suggestion, do you mean you want a type-ahead autocomplete on a login form (i.e. once you type a few characters of your user name, the application will show all user names matching the supplied user name), or do you you mean a suggestion box that provides potential alternate user names if new user supplies an existing user name?
If you're looking for the first, I would recommend avoiding this. By providing a server-side autocomplete for user names, you are providing a simple way to access the names of all users in your system and reducing security (as people trying to access your site without permission will only need to determine a password instead of a user name and password).
If it's the second, one common approach is to append numbers at the end of an existing user name to provide a user name that does not exist. I would recommend doing this in a combination of MySQL and whatever server-side language you are using.
First, get all user names that start with the user name that was supplied (and already exists):
SELECT user_name FROM users where user_name LIKE #userName + '%'
Then, in your server side language, do the following (pseudo-code)
let user = username supplied (already exists)
let recordset = recordset from db call (above)
i = 0
alternateCount = 0
alternatesFound = new string[5]
while (alternateCount < 5 And i < 100)
potentialName = user + i
if (recordset does not contain potentialName)
alternatesFound[alternateCount] = potentialName
alternateCount++
end if
end while
What this does is attempts to insert sucessive numbers (1,2,3) etc. to the supplied user name until it finds 5 cases where the user name is unique. It also does a maximum of 100 iterations in case user1 - user99 is taken (you could increase this but a limit isn't a bad idea.