-
Notifications
You must be signed in to change notification settings - Fork 0
Lambdas
simo-tuni edited this page Dec 12, 2022
·
18 revisions
These are the Lambda functions that functions as the projects backend:
Python libraries that are used in the project
import psycopg2 # psycopg2 is used for communicating with RDS Postgresql database
import jwt # JWT tokens are used for tracking login status in frontend
import uuid # uuid is used for variety of purposes to give unique identifiers
import bcrypt # bcrypt is used for password encryption
import yagmail # yagmail is used to send emails for account verification purposes
import boto3 # boto3 is used to communicate with the S3 Bucket
- signUp:
import json
import psycopg2
import jwt
import uuid
import bcrypt
import yagmail
import datetime
import os
def lambda_handler(event, context):
#Check the event for username, email, and password. If they are not found in the event, or if they are an empty string, raise error
if not("username" in event) or not("password" in event) or not("email" in event):
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['email'])<=0 or len(event['username'])<=0 or len(event['password'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
response = {
"statusCode": 401,
"message": "Catastrophic error"
}
try:
#Connect to the Postgresql database
conn = psycopg2.connect(
host=os.environ['host'],
database=os.environ['database'],
user=os.environ['user'],
password=os.environ['password']
)
cursor = conn.cursor()
#Check that username is not taken by another user that is pending email verification
postgreSQL_select_Query = "SELECT * FROM pending_users WHERE username=%s"
cursor.execute(postgreSQL_select_Query, (event['username'],))
user_records = cursor.fetchall()
#If username is taken by another user check the pending users creation date, if 10 minutes has passed, delete pending user
#If 10 minutes has not passed since user creation date, raise error
if user_records:
if datetime.datetime.now(datetime.timezone.utc) - user_records[0][4] > datetime.timedelta(minutes=10):
delete_query = "DELETE FROM pending_users WHERE id = %s"
cursor.execute(delete_query, (str(user_records[0][0]),))
conn.commit()
else:
response = {
"statusCode": 401,
"message": "Account with this username is already pending, check your email"
}
raise Exception(json.dumps(response))
#Check that email is not taken by another user that is pending email verification
postgreSQL_select_Query = "SELECT * FROM pending_users WHERE email=%s"
cursor.execute(postgreSQL_select_Query, (event['email'],))
user_records = cursor.fetchall()
#If email is taken by another user check the pending users creation date, if 10 minutes has passed, delete pending user
#If 10 minutes has not passed since user creation date, raise error
if user_records:
if datetime.datetime.now(datetime.timezone.utc) - user_records[0][4] > datetime.timedelta(minutes=10):
delete_query = "DELETE FROM pending_users WHERE id = %s"
cursor.execute(delete_query, (str(user_records[0][0]),))
conn.commit()
else:
response = {
"statusCode": 401,
"message": "Account with this email is already pending, check your email"
}
raise Exception(json.dumps(response))
#Check that username is not taken by another user, if it is taken raise error
postgreSQL_select_Query = "SELECT * FROM users WHERE username=%s"
cursor.execute(postgreSQL_select_Query, (event['username'],))
user_records = cursor.fetchall()
if user_records:
response = {
"statusCode": 401,
"message": "Username taken"
}
raise Exception(json.dumps(response))
#Check that email is not taken by another user, if it is taken raise error
postgreSQL_select_Query = "SELECT * FROM users WHERE email=%s"
cursor.execute(postgreSQL_select_Query, (event['email'],))
user_records = cursor.fetchall()
if user_records:
response = {
"statusCode": 401,
"message": "Email taken"
}
raise Exception(json.dumps(response))
# create uuid for user, check if it already exists, if it does make a new one until it doesn't exist (redundant, since chance of collision is minimal)
id = str(uuid.uuid4())
postgreSQL_select_Query = "SELECT * FROM pending_users WHERE id=%s"
cursor.execute(postgreSQL_select_Query, (id,))
user_records = cursor.fetchall()
while user_records:
id = str(uuid.uuid4())
postgreSQL_select_Query = "SELECT * FROM pending_users WHERE id=%s"
cursor.execute(postgreSQL_select_Query, (id,))
user_records = cursor.fetchall()
#Salt and hash password
pw = event['password'].encode()
salt = bcrypt.gensalt()
hashed = bcrypt.hashpw(pw, salt)
#Create hash used in email verification
verification_hash = uuid.uuid4().hex
except:
raise Exception(json.dumps(response))
try:
#Insert user into database as a user that needs email verification
insert_query = "INSERT INTO pending_users (id, username, email, password_hash, created_at, verification) VALUES (%s,%s,%s,%s,NOW(),%s)"
insert = (id,event['username'],event['email'], hashed.decode(), verification_hash)
cursor.execute(insert_query, insert)
conn.commit()
except:
response = {
"statusCode": 401,
"message": "Catastrophic error while creating user"
}
raise Exception(json.dumps(response))
try:
#Send email with verification link
url = "https://main.dsbrm4nuc1jgz.amplifyapp.com/user/{}/verify-1/{}".format(id, verification_hash)
contents = ["Please verify your email to access the service via the following link: <a href={}>Here</a>".format(url)]
yagmail.SMTP(os.environ['sender_email'],os.environ['sender_email_key']).send(event['email'], 'Signup email from Portfolio Pro', contents)
except:
response = {
"statusCode": 401,
"message": "Catastrophic error while sending email"
}
raise Exception(json.dumps(response))
return {
"message":"Successfully created user and sent email"
}
- logIn:
import json
import psycopg2
import jwt
import bcrypt
import os
def lambda_handler(event, context):
#Check for username and password in event, if they arent in event or they are an empty string raise error
if not("username" in event) or not("password" in event):
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['username'])<=0 or len(event['password'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
response = {
"statusCode": 401,
"message": "Catastrophic error"
}
try:
#Connect to the database
conn = psycopg2.connect(
host=os.environ['host'],
database=os.environ['database'],
user=os.environ['user'],
password=os.environ['password']
)
cursor = conn.cursor()
#Check if the user has verified their account by email, if they haven't, prompt them to check their email for the verification link by raising an error
verification_query = "SELECT * FROM pending_users WHERE username =%s"
cursor.execute(verification_query, (event['username'],))
unverified_user = cursor.fetchall()
if unverified_user:
response = {
"statusCode": 401,
"message": "User verification is in progress, please check your email for the link."
}
raise Exception(json.dumps(response))
#Select user from users table by username
query = "SELECT * FROM users WHERE username=%s"
cursor.execute(query, (event['username'],))
user = cursor.fetchall()
#If user does not exist raise error
if(len(user) == 0):
response = {
"statusCode": 401,
"message": "Could not identify user, credetials might be wrong"
}
raise Exception(json.dumps(response))
#Compare password hash to the password in event, if they do not match raise error
if not bcrypt.checkpw(event['password'].encode(), user[0][3].encode()):
response = {
"statusCode": 401,
"message": "Could not identify user, credetials might be wrong"
}
raise Exception(json.dumps(response))
#Create a JWT token that is used to check if user is logged in in frontend
token = jwt.encode({"userId": user[0][0], "email": user[0][2]}, os.environ['JWT_KEY'], algorithm='HS256')
except:
raise Exception(json.dumps(response))
return {
'token': token,
'userId': user[0][0],
"public": user[0][5],
'userUrl': user[0][6]
}
- loadPreviewComponents:
import json
import psycopg2
import os
def lambda_handler(event, context):
#Check for url and sectionId in event, if they arent in event or they are an empty string raise error
if not("url" in event) or not("sectionId" in event):
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['url'])<=0 or len(event['sectionId'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
response = {
"statusCode": 401,
"message": "Catastrophic error"
}
try:
#Connect to the database
conn = psycopg2.connect(
host=os.environ['host'],
database=os.environ['database'],
user=os.environ['user'],
password=os.environ['password']
)
cursor = conn.cursor()
#Select user by users url
postgreSQL_select_Query = "SELECT * FROM users WHERE user_url=%s"
cursor.execute(postgreSQL_select_Query, (event['url'],))
user_records = cursor.fetchall()
#If url is not found in database raise error
if(len(user_records) == 0):
response = {
"statusCode": 401,
"message": "Url not found"
}
raise Exception(json.dumps(response))
#If user has not set url public, raise error
if not user_records[0][5]:
response = {
"statusCode": 405,
"message": "No permission to access resource"
}
raise Exception(json.dumps(response))
#Select all components in the section that user has created
postgreSQL_select_Query = "SELECT * FROM components WHERE sectionid=%s"
cursor.execute(postgreSQL_select_Query, (event['sectionId'],))
components = cursor.fetchall()
#Select section by id to grab layout and background
section_query = "SELECT * FROM sections WHERE id=%s"
cursor.execute(section_query, (event['sectionId'],))
section = cursor.fetchall()
#Create a JSON array of components
resp = []
for component in components:
print(component)
item = {
"type": component[1],
"value": component[2],
"slotid":component[3],
"posid":component[3]
}
resp.append(item)
return {
"layout": section[0][3],
"background": section[0][4],
"components": resp
}
except Exception as e:
raise Exception(json.dumps(response))
response = {
"statusCode": 401,
"message": "Catastrophic error, lambda function did not properly return"
}
raise Exception(json.dumps(response))
- loadPreviewSections:
import json
import psycopg2
import os
def lambda_handler(event, context):
#Check event for url, if not found or it is an empty string raise error
if not("url" in event):
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['url'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
response = {
"statusCode": 401,
"message": "Catastrophic error"
}
try:
#Connect to the database
conn = psycopg2.connect(
host=os.environ['host'],
database=os.environ['database'],
user=os.environ['user'],
password=os.environ['password']
)
cursor = conn.cursor()
#Select user by the users url
postgreSQL_select_Query = "SELECT * FROM users WHERE user_url=%s"
cursor.execute(postgreSQL_select_Query, (event['url'],))
user_records = cursor.fetchall()
#If url is not found in database raise error
if(len(user_records) == 0):
response = {
"statusCode": 401,
"message": "Url not found"
}
raise Exception(json.dumps(response))
#If the user has not set the url to be public, raise error
if not user_records[0][5]:
response = {
"statusCode": 405,
"message": "No permission to access resource"
}
raise Exception(json.dumps(response))
#Select all of the users sections by user id
postgreSQL_select_Query = "SELECT * FROM sections WHERE userid=%s"
cursor.execute(postgreSQL_select_Query, (user_records[0][0],))
sections = cursor.fetchall()
#Return JSON array of sections to frontend
resp = []
for section in sections:
item = {
"id": section[0],
"name": section[2],
"position":section[5]
}
resp.append(item)
return resp
except:
raise Exception(json.dumps(response))
response = {
"statusCode": 401,
"message": "Catastrophic error, lambda function did not properly return"
}
raise Exception(json.dumps(response))
- verifyPendingUser:
import json
import psycopg2
import os
def lambda_handler(event, context):
#Check event for the verification hash and userId
if not("verification" in event) or not("id" in event):
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['verification'])<=0 or len(event['id'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
try:
#Connect to the database
conn = psycopg2.connect(
host=os.environ['host'],
database=os.environ['database'],
user=os.environ['user'],
password=os.environ['password']
)
cursor = conn.cursor()
#Select the pending user that matches both the userId and verification hash
postgreSQL_select_Query = "SELECT * FROM pending_users WHERE id = %s AND verification=%s"
cursor.execute(postgreSQL_select_Query, (event['id'],event['verification']))
user_records = cursor.fetchall()
#If user is not found raise error
if len(user_records)>0:
user_records = user_records[0]
else:
response = {
"statusCode": 401,
"message": "No user found"
}
raise Exception(json.dumps(response))
#If the user exists in pending_users table, insert the user into the users table and delete the user from pending_users table
if user_records:
insert_query = """ INSERT INTO users (id, username, email, password_hash, created_at, is_public, user_url) VALUES (%s,%s,%s,%s,NOW(),%s,%s)"""
insert = (user_records[0],user_records[1],user_records[2],user_records[3], False, "")
cursor.execute(insert_query, insert)
conn.commit()
delete_query = "DELETE FROM pending_users WHERE id = %s"
cursor.execute(delete_query, (str(user_records[0]),))
conn.commit()
except:
response = {
"statusCode": 401,
"message": "User not found in pending_users"
}
raise Exception(json.dumps(response))
return {
"message":"Successfully verified user"
}
- savePortfolio:
import json
import psycopg2
import os
def lambda_handler(event, context):
#Check event for parameters, and their length, if they are not found raise error
if not("background" in event) or not("id" in event) or not("layout" in event) or not("name" in event) or not("position" in event) or not("userId" in event):
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['background'])<=0 or len(event['id'])<=0 or len(event['layout'])<=0 or len(event['name'])<=0 or len(event['userId'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
try:
#Connect to database
conn = psycopg2.connect(
host=os.environ['host'],
database=os.environ['database'],
user=os.environ['user'],
password=os.environ['password']
)
cursor = conn.cursor()
#check if user has section with given id
check_if_section_exists_for_user = "SELECT * FROM sections WHERE userid=%s"
cursor.execute(check_if_section_exists_for_user, (event['userId'],))
user_sections = cursor.fetchall()
#if user has section by given id, delete it. this also deletes components linked to the section by cascading.
if user_sections:
delete_query = "DELETE FROM sections WHERE id = %s"
cursor.execute(delete_query, (event['id'],))
conn.commit()
except:
response = {
"statusCode": 401,
"message": "Catastrophic error"
}
raise Exception(json.dumps(response))
#if user does not have section with given id create one
try:
insert_query = """INSERT INTO sections (id, userid, name, layout, background, position)
VALUES (%s,%s,%s,%s,%s,%s)
ON CONFLICT(id) DO
UPDATE SET name =%s, layout=%s,background=%s
"""
insert = (event['id'],event['userId'],event['name'],event['layout'],event['background'],event['position'],event['name'],event['layout'],event['background'],)
cursor.execute(insert_query, insert)
conn.commit()
except Exception as e:
print(e)
response = {
"statusCode": 401,
"message": "Catastrophic error while creating sections"
}
raise Exception(json.dumps(response))
try:
#insert components to the components table, linked to sections table by sectionid
for item in event['data']:
insert_query = "INSERT INTO components (sectionid, type, value, slotid, posid) VALUES (%s,%s,%s,%s,%s)"
insert = (event['id'],item['type'],item['value'],item['slotid'],item['posid'],)
cursor.execute(insert_query, insert)
conn.commit()
except Exception as e:
response = {
"statusCode": 401,
"message": "Catastrophic error while creating components"
}
raise Exception(json.dumps(response))
return {
"message":"Successfully saved user sections and components"
}
- loadSections:
import json
import psycopg2
import os
def lambda_handler(event, context):
#Check event for parameters, and their length, if they are not found raise error
if not("userId" in event):
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['userId'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
try:
#Connect to database
conn = psycopg2.connect(
host=os.environ['host'],
database=os.environ['database'],
user=os.environ['user'],
password=os.environ['password']
)
cursor = conn.cursor()
#Select all user sections by user id
postgreSQL_select_Query = "SELECT * FROM sections WHERE userid=%s"
cursor.execute(postgreSQL_select_Query, (event['userId'],))
sections = cursor.fetchall()
#Make a JSON array
resp = []
for section in sections:
item = {
"id": section[0],
"name": section[2],
"position":section[5]
}
resp.append(item)
return resp
except:
response = {
"statusCode": 401,
"message": "Catastrophic error when selecting user sections"
}
raise Exception(json.dumps(response))
return {
"statusCode": 401,
"message": "Catastrophic error, lambda function did not properly return"
}
- loadComponents:
import json
import psycopg2
import os
def lambda_handler(event, context):
#Check event for parameters, and their length, if they are not found raise error
if not("sectionId" in event):
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['sectionId'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
try:
#Connect to the database
conn = psycopg2.connect(
host=os.environ['host'],
database=os.environ['database'],
user=os.environ['user'],
password=os.environ['password']
)
cursor = conn.cursor()
#Select all components in section by sectionId
postgreSQL_select_Query = "SELECT * FROM components WHERE sectionid=%s"
cursor.execute(postgreSQL_select_Query, (event['sectionId'],))
components = cursor.fetchall()
#Select section by sectionId to grab layout and background
section_query = "SELECT * FROM sections WHERE id=%s"
cursor.execute(section_query, (event['sectionId'],))
section = cursor.fetchall()
#Make a JSON array for components
resp = []
for component in components:
print(component)
item = {
"type": component[1],
"value": component[2],
"slotid":component[3],
"posid":component[3]
}
resp.append(item)
return {
"layout": section[0][3],
"background": section[0][4],
"components": resp
}
except:
response = {
"statusCode": 401,
"message": "Catastrophic error when selecting user sections"
}
raise Exception(json.dumps(response))
return {
"statusCode": 401,
"message": "Catastrophic error, lambda function did not properly return"
}
- deleteSection:
import json
import psycopg2
import os
def lambda_handler(event, context):
#Check event for parameters, and their length, if they are not found raise error
if not("userId" in event) or not("sectionId" in event):
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['userId'])<=0 or len(event['sectionId'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
#Default response
response = {
"statusCode": 401,
"message": "Catastrophic error"
}
try:
#Connect to database
conn = psycopg2.connect(
host=os.environ['host'],
database=os.environ['database'],
user=os.environ['user'],
password=os.environ['password']
)
cursor = conn.cursor()
#check if user has section with given id
check_if_section_exists_for_user = "SELECT * FROM sections WHERE userid=%s"
cursor.execute(check_if_section_exists_for_user, (event['userId'],))
user_sections = cursor.fetchall()
#if user has section by given id, delete it. this also deletes components linked to the section by cascading.
if user_sections:
try:
delete_query = "DELETE FROM sections WHERE id = %s"
cursor.execute(delete_query, (event['sectionId'],))
conn.commit()
return {
"message": "Successfully deleted section"
}
except:
response = {
"statusCode": 401,
"message": "Catastrophic error while deleting section"
}
except:
raise Exception(json.dumps(response))
return {
"statusCode": 401,
"message": "No sections found with given parameters"
}
- deleteAccount:
import json
import psycopg2
import os
import bcrypt
def lambda_handler(event, context):
#Check event for parameters, and their length, if they are not found raise error
if not("userId" in event) or not("password" in event):
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['userId'])<=0 or len(event['password'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
try:
#Connect to the database
conn = psycopg2.connect(
host=os.environ['host'],
database=os.environ['database'],
user=os.environ['user'],
password=os.environ['password']
)
cursor = conn.cursor()
#Select user by id, if no user is found, raise error
query = "SELECT * FROM users WHERE id=%s"
cursor.execute(query, (event['userId'],))
user = cursor.fetchall()
if(len(user) == 0):
response = {
"statusCode": 401,
"message": "Could not identify user, credetials might be wrong"
}
raise Exception(json.dumps(response))
#Check if password and hash match, if they dont, raise error
if not bcrypt.checkpw(event['password'].encode(), user[0][3].encode()):
response = {
"statusCode": 401,
"message": "Could not identify user, credetials might be wrong"
}
raise Exception(json.dumps(response))
#If they match, delete user account
else:
delete_query = "DELETE FROM users WHERE id = %s"
cursor.execute(delete_query, (str(event['userId']),))
conn.commit()
return {
"message":"Account successfully deleted"
}
except:
response = {
"statusCode": 401,
"message": "Failed to delete account"
}
raise Exception(json.dumps(response))
response = {
"statusCode": 401,
"message": "Lambda function did not properly return"
}
raise Exception(json.dumps(response))
- getSignedUrl:
import json
import boto3
import os
def lambda_handler(event, context):
#Check event for parameters, and their length, if they are not found raise error
if not("fileName" in event) or not ("fileType" in event):
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['fileName'])<=0 or len(event['fileType'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
#Connect to S3 and generate a link that frontend can upload files to
try:
s3 = boto3.client('s3',
aws_access_key_id=os.environ['S3_AWS_ACCESS_KEY_ID'],
aws_secret_access_key=os.environ['S3_AWS_SECRET_ACCESS_KEY'],
region_name=os.environ['S3_REGION']
)
url = s3.generate_presigned_url(
ClientMethod='put_object',
Params={
'Bucket': 'portfoliopro',
'Key': event['fileName'],
'ContentType': event['fileType']
},
ExpiresIn=36000
)
except:
response = {
"statusCode": 401,
"message": "Catastrophic error while accessing S3 bucket"
}
raise Exception(json.dumps(response))
return {
"url": url
}
- updatePreviewStatus:
import json
import psycopg2
import os
def lambda_handler(event, context):
print(event)
#Check event for parameters, and their length, if they are not found raise error
if not("userId" in event):
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['userId'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
try:
#Connect to the database
conn = psycopg2.connect(
host=os.environ['host'],
database=os.environ['database'],
user=os.environ['user'],
password=os.environ['password']
)
cursor = conn.cursor()
#If 'is_public' is found in event, update users public status
if ("is_public" in event):
print("is_public is " + str(event['is_public']))
insert_query = "UPDATE users SET is_public=%s WHERE id=%s"
cursor.execute(insert_query, (event['is_public'], event['userId']),)
conn.commit()
#If 'url' is found in event, update users preview url
if ("url" in event):
insert_query = "UPDATE users SET user_url=%s WHERE id=%s"
cursor.execute(insert_query, (event['url'], event['userId']),)
conn.commit()
except Exception as e:
print(e)
response = {
"statusCode": 401,
"message": "Catastrophic error"
}
raise Exception(json.dumps(response))
return {
"message":"Preview status update successful"
}
- verifyEmail:
import json
import psycopg2
import os
def lambda_handler(event, context):
#Check event for parameters, and their length, if they are not found raise error
if not("userId" in event) or not("updateHash" in event):
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['userId'])<=0 or len(event['updateHash'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
#Default response
response = {
"statusCode": 401,
"message": "Catastrophic error while trying to update email"
}
try:
#Connect to database
conn = psycopg2.connect(
host=os.environ['host'],
database=os.environ['database'],
user=os.environ['user'],
password=os.environ['password']
)
cursor = conn.cursor()
#Select user by id and email update hash
postgreSQL_select_Query = "SELECT * FROM users WHERE id = %s AND update_hash=%s"
cursor.execute(postgreSQL_select_Query, (event['userId'],event['updateHash']))
user_records = cursor.fetchall()
#If user not found, raise error
if not user_records:
raise Exception(json.dumps(response))
#Update user's email and set pending email and pending email verificarion hash to null
update_query = "UPDATE users SET email=%s,update_hash=%s,pending_email=%s WHERE id=%s"
cursor.execute(update_query, (user_records[0][8], None, None, event['userId']),)
conn.commit()
except Exception as e:
raise Exception(json.dumps(response))
return {
"message":"Email has been successfully updated"
}
- updatePassword:
import json
import psycopg2
import bcrypt
import os
def lambda_handler(event, context):
#Check event for parameters, and their length, if they are not found raise error
if not("userId" in event) or not("oldpassword" in event) or not("newpassword" in event):
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['userId'])<=0 or len(event['oldpassword'])<=0 or len(event['newpassword'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
#Default response
response = {
"statusCode": 401,
"message": "Catastrophic error while updating password"
}
try:
#Connect to the database
conn = psycopg2.connect(
host=os.environ['host'],
database=os.environ['database'],
user=os.environ['user'],
password=os.environ['password']
)
cursor = conn.cursor()
#Select user by id
query = "SELECT * FROM users WHERE id=%s"
cursor.execute(query, (event['userId'],))
user = cursor.fetchall()
#If user was not found raise error
if not user:
response = {
"statusCode": 401,
"message": "Catastrophic error, could not find user"
}
raise Exception(json.dumps(response))
#Check if oldpassword and password hash match
#If they match, salt and hash newpassword and store it in the database
if bcrypt.checkpw(event['oldpassword'].encode(), user[0][3].encode()):
pw = event['newpassword'].encode()
salt = bcrypt.gensalt()
hashed = bcrypt.hashpw(pw, salt)
cursor = conn.cursor()
insert_query = "UPDATE users SET password_hash=%s WHERE id=%s"
cursor.execute(insert_query, (hashed.decode(), event['userId']),)
conn.commit()
return {
"message":"Password updated"
}
response = {
"statusCode": 401,
"message": "User credentials do not match"
}
raise Exception(json.dumps(response))
except:
raise Exception(json.dumps(response))
response = {
"statusCode": 401,
"message": "Lambda function did not properly return"
}
raise Exception(json.dumps(response))
- updateEmail:
import json
import psycopg2
import yagmail
import uuid
import os
def lambda_handler(event, context):
#Check event for parameters, and their length, if they are not found raise error
if not("userId" in event) or not("newEmail" in event):
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['userId'])<=0 or len(event['newEmail'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
#Default response
response = {
"statusCode": 401,
"message": "Catastrophic error while trying to update email"
}
try:
#Connect to the database
conn = psycopg2.connect(
host=os.environ['host'],
database=os.environ['database'],
user=os.environ['user'],
password=os.environ['password']
)
cursor = conn.cursor()
#Check if the new email is taken by someone already
postgreSQL_select_Query = "SELECT * FROM users WHERE email=%s"
cursor.execute(postgreSQL_select_Query, (event['newEmail'],))
user_records = cursor.fetchall()
if user_records:
response = {
"statusCode": 401,
"message": "Account with this email already exists"
}
raise Exception(json.dumps(response))
#Check if the new email is taken by a pending user already
postgreSQL_select_Query = "SELECT * FROM pending_users WHERE email=%s"
cursor.execute(postgreSQL_select_Query, (event['newEmail'],))
user_records = cursor.fetchall()
if user_records:
response = {
"statusCode": 401,
"message": "Account with this email already exists"
}
raise Exception(json.dumps(response))
#Create a hash that is used for verification
verification_hash = uuid.uuid4().hex
#Update users pending email and update hash with new values
update_query = "UPDATE users SET update_hash=%s, pending_email=%s WHERE id=%s"
cursor.execute(update_query, (verification_hash, event['newEmail'], event['userId']),)
conn.commit()
#Create a url for the user for email verification
url = "https://main.dsbrm4nuc1jgz.amplifyapp.com/user/{}/verify-2/{}".format(event['userId'], verification_hash)
contents = ["Please verify your email to update it: <a href={}>Here</a>".format(url)]
#Send email
yagmail.SMTP(os.environ['sender_email'],os.environ['sender_email_key']).send(event['newEmail'], 'Email update verification', contents)
except:
raise Exception(json.dumps(response))
return {
"message":"Check your email to verify updated email"
}
- authorizer:
import json
import jwt
import os
def lambda_handler(event, context):
#Check event for token and token length
if not("authorizationToken" in event):
response = {
"statusCode": 401,
"body": "Missing arguments"
}
raise Exception(json.dumps(response))
if len(event['authorizationToken'])<=0:
response = {
"statusCode": 401,
"message": "Missing arguments"
}
raise Exception(json.dumps(response))
try:
#Split authorizationToken to token and userId
token, userId = event['authorizationToken'].split(',')
#Check that userId encoded in token is same as the userId in authorizationToken. If they match allow access to resource.
decodedToken = jwt.decode(token, os.environ['JWT_KEY'], algorithms=["HS256"])
if userId == decodedToken['userId']:
auth='Allow'
else:
auth = 'Deny'
#authResponse has to be in this format for AWS
authResponse = {
"principalId": "abc123",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Action": "execute-api:Invoke",
"Resource": [
"arn:aws:execute-api:eu-north-1:372576978893:x4hw8n8xca/*/*/user/*"
],
"Effect": auth}
]
}
}
except:
response = {
"statusCode": 500,
"body": "Something went wrong"
}
raise Exception(json.dumps(response))
return authResponse