Upload files s3 with python and javascript

I need urgent help.
I am trying to create a website that can upload images to s3.
For this use javascript as follows:

<html>
<body>

<h1>Edit your account</h1>

<hr />

<h2>Your avatar</h2>

<input type="file" id="file_input"/>
<p id="status">Please select a file</p>
<img style="border:1px solid gray;width:300px;"  id="preview"        src="../static/media/iconoApp.jpg" />

<h2>Your information</h2>

{% csrf_token %}

   <hr />
   <h2>Save changes</h2>

   <input type="submit" value="Update profile" />
   </form>


  <script type="text/javascript">
  /*
      Function to carry out the actual PUT request to S3 using the    signed    request from the Python app.
  */
  function upload_file(file, signed_request, url){

      var xhr = new XMLHttpRequest();
      xhr.open("PUT", signed_request);
      xhr.setRequestHeader('x-amz-acl' ,'public-read');
      xhr.onload = function() {

          if (xhr.status === 200) {
              document.getElementById("preview").src = url;            
              document.getElementById("avatar_url").value = url;
          }
     };
     xhr.onerror = function() {
     alert("Could not upload file."); 
   };
   xhr.send(file);
 }
 /*
     Function to get the temporary signed request from the Python app.
     If request successful, continue to upload the file using this      signed request.
 */
 function get_signed_request(file){

     var xhr = new XMLHttpRequest();

     xhr.open("GET", "/sign_s3?      file_name="+file.name+"&file_type="+file.type);
     xhr.onreadystatechange = function(){
         if(xhr.readyState === 4){
              if(xhr.status === 200){

                 var response = JSON.parse(xhr.responseText);
                 upload_file(file, response.signed_request, response.url);
            }
            else{
               alert("Could not get signed URL.");
           }
       }
   };
   xhr.send();
 }
 /*
     Function called when file input updated. If there is a file   selected, then
    start upload procedure by asking for a signed request from the app.
 */
  function init_upload(){

      var files = document.getElementById("file_input").files;
      var file = files[0];

      if(file == null){
           alert("No file selected.");
           return;
      } 
      else {
          get_signed_request(file);
      } 
    }
 /*
   Bind listeners when the page loads.
 */
  (function() {
      document.getElementById("file_input").onchange = init_upload;
   })();
 </script>
 </body>
 </html>

Then, on the server side, impletento the following in python:

def sign(key, msg):
    return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest()

def get_signature_key(key, dateStamp, regionName, serviceName):
    kDate = sign(("AWS4" + key).encode("utf-8"), dateStamp)
    kRegion = sign(kDate, regionName)
    kService = sign(kRegion, serviceName)
    kSigning = sign(kService, "aws4_request")
    return kSigning

def sign_s3(request):
    method = 'GET'
    service = 's3'
    host = 'imagenesprueba.s3.amazonaws.com'
    region = 'eu-central-1'
    endpoint = 'imagenesprueba.s3-website.eu-central-1.amazonaws.com'

    AWS_ACCESS_KEY = os.environ.get('AWS_ACCESS_KEY')
    AWS_SECRET_KEY = os.environ.get('AWS_SECRET_KEY')
    S3_BUCKET = os.environ.get('S3_BUCKET')


    t = datetime.datetime.utcnow()
    amzdate = t.strftime('%Y%m%dT%H%M%SZ')
    datestamp = t.strftime('%Y%m%d')

    #-------------------------------------------------
    # PASO 1 : Creacion de request canonico
    #-------------------------------------------------

    canonical_uri = '/imagenesprueba/'

    canonical_headers = 'host:' + host + 'n'

    signed_headers = 'host'

    algoritmo = 'AWS4-HMAC-SHA256'
    credencial_scope = datestamp + '/' + region + '/' + service + '/' +    'aws4_request'

    canonical_querystring = 'Action=s3:PutObject&Version=2012-10-17'
    canonical_querystring +=  '&X-Amz-Algorithm=' + algoritmo

    canonical_querystring += '&X-Amz-Credential=' +    urllib.quote_plus(AWS_ACCESS_KEY + '/' + credencial_scope)

    canonical_querystring += '&X-Amz-Date=' + amzdate

    canonical_querystring += '&X-Amz-Expires=30'

    canonical_querystring += '&X-Amz-SignedHeaders=' + signed_headers


    payload_hash = hashlib.sha256('').hexdigest()


    canonical_request = method + 'n' + canonical_uri + 'n' +     canonical_querystring + 'n' + canonical_headers + 'n' + signed_headers +    'n' + payload_hash

    #-------------------------------------------------
    # PASO  2: Creacion del string de la firma
    #-------------------------------------------------
    string_to_sign = algoritmo + 'n' + amzdate + 'n' +    credencial_scope + 'n' + hashlib.sha256(canonical_request).hexdigest()

    #-------------------------------------------------
    # PASO 3 : Calculo de la firma
    #-------------------------------------------------
    signing_key = get_signature_key(AWS_SECRET_KEY, datestamp, region, service)

    signature = hmac.new(signing_key, (string_to_sign).encode('utf-8'), hashlib.sha256).hexdigest()

    #-------------------------------------------------
    # PASO 4 : Anade la firma al request
    #-------------------------------------------------
    canonical_querystring += '&X-Amz-Signarure=' + signature

    #-------------------------------------------------
    # PASO 5 : Envio del request
    #-------------------------------------------------
    request_url = endpoint + '?' + canonical_querystring


    return HttpResponse(json.dumps({'url' : request_url,   'signed_request' : signature}))

I always returns an html 403 or 503 error.
Can someone help me out?

Thanks


Source: javascript

Leave a Reply