A New Collection of Thoughtful Learning Apps — Now Available on iOS & Android

Image
I’m excited to share a set of mobile apps I’ve recently completed and published on both the Google Play Store and the Apple App Store. These apps are designed with a simple goal in mind: to make meaningful, structured content more accessible, whether you’re studying theology or improving your English vocabulary. 📱 Now Available on Both Platforms All apps are live and available for download: Google Play Developer Page: https://play.google.com/store/apps/dev?id=5835943159853189043 Apple App Store Developer Page: https://apps.apple.com/ca/developer/q-z-l-corp/id1888794100 📖 Theology & Confession Study Apps For those interested in Reformed theology and classical Christian teachings, I’ve developed a series of apps that present foundational texts in a clean, focused reading format: The Belgic Confession Canons of Dort Heidelberg Catechism Westminster Shorter Catechism Each app is designed to provide a distraction-free experience, making it easier to read, reflect, and revisit these im...

AWS: how to upload file to your s3 bucket via EvaporateJS in browser

Evaporate and config s3 bucket and IAM user

EvaporateJS
Config AWS s3 bucket
Managing Access Permissions to Your Amazon S3 Resources
User Access Key
In summary, create a s3 bucket, set up CORS settings and bucket policy.
 <CORSConfiguration>
     <CORSRule>
         <AllowedOrigin>https://*.yourdomain.com</AllowedOrigin>
         <AllowedOrigin>http://*.yourdomain.com</AllowedOrigin>
         <AllowedMethod>PUT</AllowedMethod>
         <AllowedMethod>POST</AllowedMethod>
         <AllowedMethod>DELETE</AllowedMethod>
         <AllowedMethod>GET</AllowedMethod>
         <ExposeHeader>ETag</ExposeHeader>
         <AllowedHeader>*</AllowedHeader>
     </CORSRule>
 </CORSConfiguration>
 
{
    "Version": "2012-10-17",
    "Id": "Policy145337ddwd",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::6681765859115:user/me"
            },
            "Action": [
                "s3:AbortMultipartUpload",
                "s3:ListMultipartUploadParts",
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::mybucket/*"
        }
    ]
} 

Main codes

an example app created via 'create-reat-app' tool.
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

const Evaporate = require('evaporate');
const crypto = require('crypto');

class App extends Component {
  onFileSelected(files) {
    var config = {
      signerUrl: 'YOURSIGNEDURL',
      aws_key: 'YOURAWSKEY',
      bucket: 'YOURBUCKETNAME',
      cloudfront: true,
      computeContentMd5: true,
      cryptoMd5Method: function (data) {
        return crypto.createHash('md5').update(Buffer.from(data)).digest('base64');  
      },
      cryptoHexEncodedHash256: function (data) {
        return crypto.createHash('sha256').update(Buffer.from(data)).digest('hex');
      }
    };
    return Evaporate.create(config)
      .then(function (evaporate) {
         var addConfig = {
           name: files[0].name,
           file: files[0],
           progress: function (progressValue) {
             console.log('Progress', progressValue);
           },
           complete: function (_xhr, awsKey) {
             console.log('Complete!');
           },
         };
         var overrides = {
            bucket: 'recordingsfortalkmeup'
         };
         evaporate.add(addConfig, overrides)
           .then(function (awsObjectKey) {
                console.log('File successfully uploaded to:', awsObjectKey);
           },
           function (reason) {
             console.log('File did not upload sucessfully:', reason);
           });
      });
  }
  render() {
    return (
      <div className="App">
        <input type='file' onChange={(e) => this.onFileSelected(e.target.files)
 }/>
      </div>
    );
  }
}

export default App;

Signer URL

Create a lambda function to do the signature process.
Signing AWS Requests with Signature Version 4
'use strict';
console.log('Loading upload signature function');

const crypto = require("crypto");

function hmac(key, string){
    const hmac = crypto.createHmac('sha256', key);
    hmac.end(string);
    return hmac.read();
}

exports.handler = function(event, context, callback) {
    console.log(JSON.stringify(event));
    let to_sign = event.queryStringParameters.to_sign;
    let timestamp = event.queryStringParameters.datetime.substr(0, 8);
    console.log(to_sign);    
    console.log('date:', timestamp);
    console.log('aws secret key:', process.env.AWS_SECRET);
    console.log('region:', process.env.AWS_REGION);
    console.log('service:s3');
    let dateKey = hmac('AWS4' + process.env.AWS_SECRET, timestamp);
    let dateRegionKey = hmac(dateKey, process.env.AWS_REGION);
    let dateRegionServiceKey = hmac(dateRegionKey, 's3');
    let signingKey = hmac(dateRegionServiceKey, 'aws4_request');
    let signature = hmac(signingKey, to_sign).toString('hex');
    console.log('Created signature "' + signature + '" from ' + to_sign);
    var response = {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Origin" : "*",
            "Content-Type": "text/html"
        },
        body: signature
    };
    callback(null, response);
};
 
Build an rest API bind with this Lambda function and deploy it, then you will get an invoke url which will be your signer url.
Build an API Gateway API with Lambda Integration
APIGATEWAY

Test

upload
Everything is ok, you will find new uploaded file in your s3 bucket.
s3bucket

Download file from s3 bucket

❤️ Support This Blog


If this post helped you, you can support my writing with a small donation. Thank you for reading.


Comments

Popular Posts

2026 Begins: Choosing to Stay on the Path as a Blogger

A New Collection of Thoughtful Learning Apps — Now Available on iOS & Android

How to Prepare App Preview Videos and Screenshots for App Store Connect