From 37a0247acc23428347f602066516cef48d4a0896 Mon Sep 17 00:00:00 2001 From: Aaron Gutierrez Date: Mon, 15 May 2023 21:02:21 -0700 Subject: [PATCH] Initial commit --- .gitignore | 2 ++ README.md | 16 ++++++++++ requirements.txt | 5 ++++ urlshorten.py | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 requirements.txt create mode 100644 urlshorten.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3086a6e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +venv +urlshorten.zip diff --git a/README.md b/README.md new file mode 100644 index 0000000..05b6553 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# URL Shortener +There are many; this is mine. + +## Bundling for upload +Create a virtual environment + python -m venv venv + source venv/bin/activate + +Install dependencies + python -m pip install -r requirements.txt + +Zip it all up + cd venv/lib/python3.10/site-packages + zip -r ../../../../urlshorten.zip . + cd ../../../../ + zip -g urlshorten.zip urlshorten.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..4fa7a79 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +certifi==2023.5.7 +charset-normalizer==3.1.0 +idna==3.4 +requests==2.29.0 +urllib3==1.26.15 diff --git a/urlshorten.py b/urlshorten.py new file mode 100644 index 0000000..8b4d55b --- /dev/null +++ b/urlshorten.py @@ -0,0 +1,76 @@ +import boto3 +import os +import requests + +from base64 import b64decode +from botocore.exceptions import ClientError + +dynamodb = boto3.resource('dynamodb', region_name='us-west-2') + +ENCRYPTED = os.environ['RECAPTCHA_SECRET'] +# Decrypt code should run once and variables stored outside of the function +# handler so that these are decrypted once per container +RECAPTCHA_SECRET = boto3.client('kms').decrypt(CiphertextBlob=b64decode(ENCRYPTED))['Plaintext'] + +def lambda_handler(event, context): + table = dynamodb.Table('urlshorten') + + if 'from' in event and 'to' in event: + captcha_data = { + 'secret': RECAPTCHA_SECRET, + 'response': event['g-recaptcha-response'], + 'remoteip': event['remoteip'] + } + + verify = requests.get('https://www.google.com/recaptcha/api/siteverify', + params=captcha_data) + if not (verify.status_code == 200 and verify.json()['success']): + return { + 'status': 'error', + 'error': verify.json() + } + + ssl = event['to'][:5].lower() == 'https' + + url = ('https://' if ssl else 'http://') + event['to'].split('://')[-1] + + try: + table.put_item( + Item={ + 'key': event['from'], + 'value': url + }, + ConditionExpression='attribute_not_exists(#key)', + ExpressionAttributeNames={ + '#key': 'key' + } + ) + except ClientError as e: + return { + 'status': 'error', + 'error': e.response['Error'] + } + except KeyError: + return { + 'status': 'error', + 'error': 'Invalid Request', + 'location': '/' + } + else: + return { + 'status': 'ok' + } + + try: + response = table.get_item(Key={ 'key': event['shortUrl'] }) + location = response['Item']['value'] + except ClientError as e: + return e.response['Error'] + except KeyError: + return { + 'location': '/' + } + else: + return { + 'location': response['Item']['value'] + }