GithubHelp home page GithubHelp logo

Comments (7)

wx2228 avatar wx2228 commented on July 28, 2024 1

@philfreo I mean stefan's code got all configs in one place. Personally i like this way better, but you definitely did a good job here, cheers.

from django-froala-editor.

philfreo avatar philfreo commented on July 28, 2024

I got it working with code like this, below.

It relies on boto3 (see docs).

import boto3

def generate_s3_presigned_post(bucket, key_start, acl='public-read'):
    """Generate an AWS signature for presigned POST requests.

    This signed data allows file uploads directly from the browser to S3.

    This approach relies on a "starts-with" key name condition (which boto3
    generates automatically).
    """

    s3 = boto3.client(
        's3',
        aws_access_key_id=app.config['AWS_UPLOAD_ACCESS_KEY_ID'],
        aws_secret_access_key=app.config['AWS_UPLOAD_SECRET_ACCESS_KEY']
    )

    # http://boto3.readthedocs.io/en/latest/reference/services/s3.html#S3.Client.generate_presigned_post
    data = s3.generate_presigned_post(
        bucket,
        key_start + '${filename}',

        Conditions=[
            # There's not an explicit 'starts-with' value for the key/filename because boto3
            # adds this automatically based on the second parameter (Key) above.
            {'acl': acl},
            {'success_action_status': '201'},
            {'x-requested-with': 'xhr'},
            ['starts-with', '$content-type', ''], # Allow any content-type
            ['content-length-range', 0, 20000000], # An upper bound on how large of files we'll accept (20MB)
        ],

        # Uploads must happen within 24h of generation
        ExpiresIn=60*60*24,
    )

    # Add other values that the browser JS will need to include in a POST
    data['acl'] = acl
    data['key_start'] = key_start

    return data

from django-froala-editor.

stefanneculai avatar stefanneculai commented on July 28, 2024

Sorry for the late reply. Here is a way of doing it and it will be available in the Python SDK shortly.

"""
        Get signature for S3.
        Parameters:
            config: dict
            {
                bucket: 'bucketName',
                //http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
                region: 's3',
                keyStart: 'editor/',
                acl: 'public-read',
                accessKey: 'YOUR-AMAZON-S3-PUBLIC-ACCESS-KEY',
                secretKey: 'YOUR-AMAZON-S3-SECRET-ACCESS-KEY'
            }
         Return:
            dict:
            {
                bucket: bucket,
                region: region,
                keyStart: keyStart,
                params: {
                    acl: acl,
                    policy: policy,
                    'x-amz-algorithm': 'AWS4-HMAC-SHA256',
                    'x-amz-credential': xAmzCredential,
                    'x-amz-date': xAmzDate,
                    'x-amz-signature': signature
                }
            }
        """

        # Check default region.
        config['region'] = config['region'] if 'region' in config else 'us-east-1'
        config['region'] = 'us-east-1' if config['region'] == 's3' else  config['region']

        bucket = config['bucket']
        region = config['region']
        keyStart = config['keyStart']
        acl = config['acl']

        # These can be found on your Account page, under Security Credentials > Access Keys.
        accessKeyId = config['accessKey']
        secret = config['secretKey']

        dateString = datetime.datetime.now().strftime("%Y%m%d") # Ymd format.

        credential = '/'.join([accessKeyId, dateString, region, 's3/aws4_request'])
        xAmzDate = dateString + 'T000000Z'

        # Build policy.
        policy = {
            # 5 minutes into the future
            'expiration': (datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime("%Y-%m-%dT%H:%M:%S.000Z"),
            'conditions': [
                {'bucket': bucket},
                {'acl': acl },
                {'success_action_status': '201'},
                {'x-requested-with': 'xhr'},
                {'x-amz-algorithm': 'AWS4-HMAC-SHA256'},
                {'x-amz-credential': credential},
                {'x-amz-date': xAmzDate},
                ['starts-with', '$key', keyStart],
                ['starts-with', '$Content-Type', ''] # Accept all files.
            ],
        }
        # python 2-3 compatible:
        try:
            policyBase64 = base64.b64encode(json.dumps(policy).encode()).decode('utf-8') # v3
        except Exception:
            policyBase64 = base64.b64encode(json.dumps(policy)) # v2

        # Generate signature.
        dateKey = Utils.hmac('AWS4' + secret, dateString);
        dateRegionKey = Utils.hmac(dateKey, region)
        dateRegionServiceKey = Utils.hmac(dateRegionKey, 's3')
        signingKey = Utils.hmac(dateRegionServiceKey, 'aws4_request')
        signature = Utils.hmac(signingKey, policyBase64, True)

        return {
            'bucket': bucket,
            'region': 's3-' + region if region != 'us-east-1' else 's3',
            'keyStart': keyStart,
            'params': {
                'acl': acl,
                'policy': policyBase64,
                'x-amz-algorithm': 'AWS4-HMAC-SHA256',
                'x-amz-credential': credential,
                'x-amz-date': xAmzDate,
                'x-amz-signature': signature
            }
        }

from django-froala-editor.

philfreo avatar philfreo commented on July 28, 2024

Any reason for not going with a somewhat simpler solution like mine above? It offloads the harder stuff to boto3 which is basically the standard for working with AWS in Python.

from django-froala-editor.

wx2228 avatar wx2228 commented on July 28, 2024

@philfreo you didn't define region in the code, it's gonna use the default one. @stefanneculai code is huge but actually gives more options.

from django-froala-editor.

philfreo avatar philfreo commented on July 28, 2024

@wx2228 I don't believe you are correct, I think you can specify any region you want as part of the upload URL passed to the Froala via the uploadURL option. This would be done in JavaScript, keeping the server implementation as simple as possible.

from django-froala-editor.

stefanneculai avatar stefanneculai commented on July 28, 2024

In the meanwhile, we released a Python SDK which comes with an easier way of uploading to S3:
https://www.froala.com/wysiwyg-editor/docs/sdks/python
https://www.froala.com/wysiwyg-editor/docs/sdks/python/image-s3-upload

from django-froala-editor.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.