서승완
Builds for 1 pipeline passed in 29 minutes 56 seconds

feat: add s3 events lambda function

deprecate cloudfront from file download due to cache issue
add lambda function which triggered when s3 put events
update file size to database when upload
update file name in s3 metadata when rename
......@@ -23,7 +23,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SECRET_KEY = 'wfs076redt^-5_*dw6!_dqz*2z!a_#()33y@r_q7&+4r_40h9$'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG = False
ALLOWED_HOSTS = ['127.0.0.1', 'khubox-api.khunet.net']
......@@ -49,7 +49,7 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'khubox.auth.AuthMiddleware',
'khubox.middlewares.auth.AuthMiddleware',
]
ROOT_URLCONF = 'config.urls'
......@@ -129,9 +129,6 @@ STATIC_URL = '/static/'
# Custom Settings
S3_BUCKET = 'khubox-files'
CDN_PATH = 'https://khubox-files.khunet.net'
CLOUDFRONT_KEY_ID = 'APKAJ3FOBWI34OZJTXJQ'
CLOUDFRONT_KEY_PRIVATE = '-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA18VtzURs+fQev5L00LRwRbJaObQI4kfJCIsOE7eWSOqq4Akh\nA7fI6vs3z8orXBvgc+k6GgAHrIdNwckxoQuTsCxrTDm1104qy1T4JkVxkIBYHJgH\nGzKUloK5IqdmcYbOK7IQeHJ2gR9Mv/3oKUytJSsrbM9k4oLrsxGpyEuJeHIg28aP\nwhoVWmBGcPu48l4aYAZEVY7LZRJSOQ9y7Lf8FS1u7Xtw1P91gEaqrqVXqRWY02C8\nsixpJJuiAPnM3rpcpVNlAaPdDkWmaWYJoJDOlce7Dmx1a9Ckr24krM//vpEljurC\nGml0AsHpL8LE9msM5VA+miCxCz/K+wDgm2xvvQIDAQABAoIBAFmP3pLceyuJVBYK\n5smWjB+x91eKTkG2sFB2f8JZau0bUxApWeXULHa1DiaW8UaLX7BdN7vBFW5cvz7X\nx1zklEoFNghuz/btwD+kJlikbI4hZ/F+fTyh0yFiY3xp5dDrtrpWcBW+1UeleVMc\nDnjOFfSepajFsUeANlue0k2MZSRz34s2T2scV5ZkooqdXddYUF/wDhefYm6uvCgI\nPyvY/mbJTyhte/xagY/m6yzk5gxgad0qP2ZZrHhLLMlJ/GEZToWDxD2xUei61NQT\nFFc5ZutkAE6fVb3I4SJUBSX5fl0tTMz4Aak1GP2phMhjZyjYnQMq8kvL4BNFb7gp\nary8W/UCgYEA+eKkfjjlPsEx6yHMhD7pAwy/MpUqJmF5LMxIG+qfd+GZMQ2oucn5\npUAwBHP7BD6E9H7/7jdjnCiO+iPrzM9vNLfqsdCtPWzoFYJp/6Fv002uX8seNYvJ\nQyQqrM85LYIghhnkcmJMA8GR/Iu5ZEeE2BkAl9T2EKclzmB62d/ki6MCgYEA3Q0V\nz08IEwSJW+jEsOM+XGg2YkNqCVKGQD9n4CPx0TFVJxfqFl2nVwlN2hfrlJLUQ9+l\nfXnS5AW3tE88t9we+ea0saJZEqqlm/rGsfTV/twS9cWSgvG5fTzhUbu9/ElMU29L\nmydQfWTvCup7zCuQtgwM5ZRtPwuKsI8urUg6zR8CgYAt0coZvvMCI8i0dbkbkrGF\nNqQkcUeOTBc9CKQ8QjRFdh9x6DBFCOz2ySNE3cNsTs5wSo1BL/Ta4HD/GvEU2ABr\nKUImor3xYnPX5dbr4b0wgLD1rbf3V49q+Um98C1q086E6GCEPNP1aFwNc81lvtt0\nCHmcXZdVDGEZS4WbR7uPgwKBgBO/moY12lPQoPDsH75p3uVkjg9DVJLWo5XT1FTr\nASyeSqw+b7Rl05BsDV+BqZNRdtNFhMRsANJMTHg4aAVJDh9nZBdGmMyZIEiKI/w8\nEm49fRgl+YvnSpoMuViS/EswxTfjBo8q+P7q6IxCHKNF9Ry+gNx14TizsEVL1XC3\ntkEjAoGBAMyp7wdPobJMXcclRVq6rqHs9OMcnZAveVKyxNgDbZu4OB5X4xTxGEYT\nNZQ0MFf/HcwlnH7797gVQeqF9dlqUJYe+Fc8lc/Rcwta/4R5uMgri9t8RKN91YKF\nUUFBsDEkWlkoAmfPkcrrq9cLJlmSNt3ehQj4p5iAJwoVBXXa++PO\n-----END RSA PRIVATE KEY-----'
# Cors
......
import boto3
import datetime
from botocore.signers import CloudFrontSigner
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from django.conf import settings
def rsa_signer(message):
private_key = serialization.load_pem_private_key(
settings.CLOUDFRONT_KEY_PRIVATE.encode('ascii'),
password=None,
backend=default_backend()
def sign_download(file_id):
s3 = boto3.client('s3')
signed_url = s3.generate_presigned_url(
'get_object',
Params={'Bucket': settings.S3_BUCKET, 'Key': file_id},
ExpiresIn=3600,
HttpMethod='GET'
)
return private_key.sign(message, padding.PKCS1v15(), hashes.SHA1())
def sign_download(url):
expire_date = datetime.datetime.utcnow() + datetime.timedelta(hours=1)
cloudfront_signer = CloudFrontSigner(settings.CLOUDFRONT_KEY_ID, rsa_signer)
signed_url = cloudfront_signer.generate_presigned_url(url, date_less_than=expire_date)
return signed_url
......@@ -52,3 +42,13 @@ def s3_copy(file_id, new_file_id):
}
obj = bucket.Object(str(new_file_id))
obj.copy(copy_source)
def s3_update_and_return_size(file_id, name):
s3 = boto3.resource('s3')
s3_object = s3.Object(settings.S3_BUCKET, file_id)
s3_object.copy_from(CopySource={'Bucket': settings.S3_BUCKET, 'Key': file_id},
ContentType='application/octet-stream',
ContentDisposition='attachment; filename=%s' % name,
MetadataDirective='REPLACE')
return s3_object.content_length
......
import os
import django
from .aws import s3_delete, s3_update_and_return_size
from .models import File
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
django.setup()
def process_upload(event, context):
file_id = event['Records'][0]['s3']['object']['key']
file = File.objects.filter(id=file_id, deleted_at__isnull=True)
# File Gone
if len(file) == 0:
s3_delete([file_id])
return
# Update
file[0].size = s3_update_and_return_size(file_id, file[0].name)
file[0].save()
import json
import uuid
from django.conf import settings
from django.utils import timezone
from ..aws import sign_upload, sign_download, s3_copy, s3_delete
from pathvalidate import sanitize_filename
from ..aws import sign_upload, sign_download, s3_copy, s3_delete, s3_update_and_return_size
from ..models import File, GroupUser
......@@ -91,7 +91,7 @@ def create(request):
owner_group_id=parent[0].owner_group_id,
uploader_id=request.user_id,
type=received['type'],
name=received['name'],
name=sanitize_filename(received['name']),
size=0,
created_at=timezone.now()
)
......@@ -178,8 +178,7 @@ def find_item(request, file_id):
# Return File
if file[0].type == 'file':
download_url = '%s/%s' % (settings.CDN_PATH, file[0].id)
download_url = sign_download(download_url)
download_url = sign_download(file[0].id)
data = {
'id': file[0].id,
'parent_id': file[0].parent_id,
......@@ -273,7 +272,8 @@ def update_item(request, file_id):
if 'name' in received:
if received['name'] == '':
return {'result': False, 'error': '이름을 제대로 입력해주세요.'}
file[0].name = received['name']
file[0].name = sanitize_filename(received['name'])
s3_update_and_return_size(file_id, file[0].name)
if 'parent_id' in received:
file[0].parent_id = received['parent_id']
if 'is_public' in received:
......
......@@ -17,6 +17,7 @@ idna==2.9
importlib-metadata==1.6.0
jmespath==0.10.0
-e git+http://khuhub.khu.ac.kr/2016104129/kappa.git@1b0e17bb6da7460d9d494828c682a5ef66736aa3#egg=kappa
pathvalidate==2.3.0
pip-tools==5.1.2
placebo==0.9.0
pycparser==2.20
......
......@@ -10,6 +10,17 @@
"vpc_config": {
"SubnetIds": ["subnet-02d51e69"],
"SecurityGroupIds": ["sg-09c30d37d6a504f5c"]
}
},
"events": [
{
"function": "khubox.lambda.process_upload",
"event_source": {
"arn": "arn:aws:s3:::khubox-files",
"events": [
"s3:ObjectCreated:Put"
]
}
}
]
}
}
......