<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bahadir Balban</title>
    <description>The latest articles on DEV Community by Bahadir Balban (@bahadirbalban).</description>
    <link>https://dev.to/bahadirbalban</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F31435%2F3892ab80-7a64-409b-91e6-3eb3619b3a0e.jpg</url>
      <title>DEV Community: Bahadir Balban</title>
      <link>https://dev.to/bahadirbalban</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bahadirbalban"/>
    <language>en</language>
    <item>
      <title>Introduction to RISC V and Assembly Language for Beginners</title>
      <dc:creator>Bahadir Balban</dc:creator>
      <pubDate>Wed, 11 Mar 2020 17:40:18 +0000</pubDate>
      <link>https://dev.to/bahadirbalban/beginner-s-introduction-to-risc-v-and-assembly-language-1m4a</link>
      <guid>https://dev.to/bahadirbalban/beginner-s-introduction-to-risc-v-and-assembly-language-1m4a</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/KBvAKHsHBW4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn what RISC V is, and basic assembly language in 15 minutes
&lt;/h2&gt;

&lt;p&gt;This is a gentle introduction to the RISC V open source instruction set architecture (ISA) for beginners.&lt;/p&gt;

&lt;p&gt;I covered how RISC V started, what the ISA is about, how assembly instructions work.&lt;/p&gt;

&lt;p&gt;The 15 minute session ends with a simple applied lab that you can conduct on a PC at home.&lt;/p&gt;

&lt;p&gt;At Tech Buzz I share quick videos and articles that get you up to speed on a new industrial subject, and enable you to build things.&lt;/p&gt;

&lt;p&gt;If you are interested in industrial tutorials feel free to check out &lt;a href="https://getbuzz.io"&gt;Tech Buzz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If people are interested I will produce more of this series. Join the RISCV course community &lt;a href="https://getbuzz.io/o/introduction-to-risc-v/u/join-open-access"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cheers!&lt;br&gt;
Bahadir&lt;/p&gt;

</description>
      <category>riscv</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>assembly</category>
    </item>
    <item>
      <title>How to divide an S3 bucket with per-customer paths and enable secure file access</title>
      <dc:creator>Bahadir Balban</dc:creator>
      <pubDate>Thu, 20 Jun 2019 23:22:01 +0000</pubDate>
      <link>https://dev.to/bahadirbalban/how-to-divide-an-s3-bucket-with-per-customer-paths-and-enable-secure-file-access-5d8b</link>
      <guid>https://dev.to/bahadirbalban/how-to-divide-an-s3-bucket-with-per-customer-paths-and-enable-secure-file-access-5d8b</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbuzz-prod-photos.global.ssl.fastly.net%2Fsaasbox%2Fimg%2F47f1f1fb-d3da-47bc-8438-91beac767d44" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbuzz-prod-photos.global.ssl.fastly.net%2Fsaasbox%2Fimg%2F47f1f1fb-d3da-47bc-8438-91beac767d44" alt="One S3 box for all customers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;You can divide a single S3 bucket into per-customer paths, and allow those customers to control read or write access, only to their own &lt;code&gt;/username&lt;/code&gt; path. You do this by giving each customer an AWS IAM user and attaching a policy that lets them only access their &lt;code&gt;/username&lt;/code&gt; path.&lt;/p&gt;

&lt;p&gt;Customers can do accelerated uploads using signed S3 urls, and make their files available to public temporarily and securely (e.g. behind a paywall).&lt;/p&gt;

&lt;p&gt;Use case: You host web apps for others, whose customers sign up to their service, and download a file they purchased from your customer’s signed S3 url. The file is hosted on your S3 bucket.&lt;/p&gt;

&lt;p&gt;If you want to go one step further and let users make available their files for download via a CDN, it is not instantly supported by Cloudfront. This is because each user has their own keys to their &lt;code&gt;/username&lt;/code&gt; path, but Cloudfront has one master key. You can’t generate a per-user Cloudfront key for a single S3 bucket the way you generate IAM keys. There is a hack for this shared below as well, or simpler: just use signed S3 urls for downloads.&lt;/p&gt;

&lt;h1&gt;
  
  
  Details
&lt;/h1&gt;

&lt;p&gt;While building &lt;a href="https://saasbox.net" rel="noopener noreferrer"&gt;SaaSBox&lt;/a&gt;, I needed to create a storage hosting solution where each customer has access to their own files, for read and write. I needed a simple solution that works well for many users. I ended up with a single S3 bucket, dividing it into customer paths starting with &lt;code&gt;/username&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here is how it works:
&lt;/h2&gt;

&lt;p&gt;Set up a single s3 bucket. Each time a new user/customer signs up, you create a new IAM user in AWS, attaching the following policy to the user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AllowGroupToSeeBucketListInTheConsole"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:ListAllMyBuckets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetBucketLocation"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::*"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AllowRootAndHomeListingOfCompanyBucket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:ListBucket"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-s3-bucket-name"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"StringEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"s3:prefix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"s3:delimiter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AllowListingOfUserFolder"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:ListBucket"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-s3-bucket-name"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"StringLike"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"s3:prefix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"${aws:username}/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"${aws:username}"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AllowAllS3ActionsInUserFolder"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:*"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-s3-bucket-name/${aws:username}/*"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The policy has the &lt;code&gt;${aws:username}&lt;/code&gt; placeholder, which means, it applies to each IAM user with the policy attached.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TIP:&lt;/strong&gt; Make sure to also tag IAM users when creating them so that you know these are users of your service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; You must attach the policy to the IAM user, not the S3 Bucket.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making S3 content private and only available via signed urls
&lt;/h3&gt;

&lt;p&gt;What you want to achieve is that your S3 bucket contents are always private, except:&lt;/p&gt;

&lt;p&gt;When your users want to, they should be able to write to their directory.&lt;/p&gt;

&lt;p&gt;They should be able to make their files public for download whenever needed (in my case right after they sell them).&lt;/p&gt;

&lt;p&gt;You achieve this using signed urls. S3 buckets support signed urls for upload and download. Here is the code you need in order to generate signed urls:&lt;/p&gt;

&lt;h3&gt;
  
  
  S3 Signed url for reading:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* S3 signed url for reading */&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get_file_read_presigned_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ftype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSignedUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getObject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s3bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;ResponseContentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ftype&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  S3 Signed url for writing:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* S3 signed url for uploading files */&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get_file_upload_presigned_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ftype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;s3bucket.url:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;s3bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSignedUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;putObject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s3bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;ACL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;authenticated-read&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;ContentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ftype&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using Cloudfront CDN for caching files
&lt;/h3&gt;

&lt;p&gt;Instead of an S3 signed url for reading, ideally you should set up cloudfront on the S3 bucket and sign urls using cloudfront. Here is how you would &lt;strong&gt;normally&lt;/strong&gt; achieve this &lt;strong&gt;for your own files&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CloudFront&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Signer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s3bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cf_accessKeyId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;s3bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cf_privateKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;twoDays&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;

&lt;span class="cm"&gt;/* Cloudfront signed url for reading */&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get_file_read_presigned_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ftype&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signedUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSignedUrl&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s3bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cdn_url&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;fpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;expires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;twoDays&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// Unix UTC timestamp for now + 2 days&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;signedUrl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, you can do accelerated uploads to S3 by using S3 signed urls for upload, and cloudfront for making them available for read.&lt;/p&gt;

&lt;p&gt;However, serving files via Cloudfront signed by your customers' keys is not an immediately possible approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fine grain access to S3 files using per-user paths by your users with Cloudfront enabled
&lt;/h3&gt;

&lt;p&gt;This is something I wanted to achieve, e.g. if I can create IAM users with per user directory access on the S3 bucket with their own keys, I would also want to serve their files using a CDN such as cloudfront, with &lt;em&gt;them&lt;/em&gt; signing the urls using their keys.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Unfortunately this is not immediately supported by Cloudfront.&lt;/em&gt; E.g. the use case is you create some master key for Cloudfront using your AWS root account and make available all files signing with your key.&lt;/p&gt;

&lt;p&gt;If you want your users to make available their own directory path on the S3 bucket using their own keys, it is not possible with Cloudfront, since you have 1 master key.&lt;/p&gt;

&lt;p&gt;The simple solution is just use S3 signed urls without cloudfront. You can serve thousands of users on a single s3 bucket!&lt;/p&gt;

&lt;p&gt;There is a workaround to using Cloudfront though and it is described at this link: &lt;a href="https://advancedweb.hu/2018/11/15/s3_signed_urls_cloudfront/" rel="noopener noreferrer"&gt;How to use S3 signed urls with Cloudfront.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  CloudFront Workaround
&lt;/h3&gt;

&lt;p&gt;By nature, S3 signed urls change each time they are generated. As a result, each new url means re-caching by Cloudfront, defeating the purpose of having a cache. Therefore what you do is, you force/hack the S3 signed url generation function to generate the same url for a period of time, fixing the time element artificially to a window. E.g. for the current hour + 1 hour, tell it to generate this specific url only. This way CF can cache the url for that period.&lt;/p&gt;

&lt;p&gt;If you directly generate the URL via CloudFront you don’t have this problem since Cloudfront has direct access to the file.&lt;/p&gt;

&lt;p&gt;But yes you can do it, by fixating the generated url by S3, and re-caching the file every few hours.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>node</category>
      <category>aws</category>
    </item>
    <item>
      <title>Learn back-end development with Node.js and Express with this free in-depth course (2.5 hours)</title>
      <dc:creator>Bahadir Balban</dc:creator>
      <pubDate>Fri, 15 Feb 2019 19:54:29 +0000</pubDate>
      <link>https://dev.to/bahadirbalban/learn-back-end-development-with-nodejs-and-express-with-this-free-in-depth-course-25-hours-22pp</link>
      <guid>https://dev.to/bahadirbalban/learn-back-end-development-with-nodejs-and-express-with-this-free-in-depth-course-25-hours-22pp</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/mG1L7C4y2c0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://getbuzz.io/c/learning-expressjs/stories/Learn-how-to-develop-a-NodeJS-application-4007962439"&gt;This course&lt;/a&gt;☝️ starts from scratch and shows you how to build a landing page, collect and manage sales leads developing an application using the CRUD pattern (create, update, delete). We develop an MVC style application with models, views, routes, controllers. If you are new to backend development and Nodejs this course is made for you.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;a href="https://getbuzz.io/c/learning-expressjs/stories/Implement-edit-update-lead-routes-6914824963"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ug-z9P_D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ywngi0o02oapz3ipra1h.png" alt="CRUD snippet from tutorial"&gt;&lt;/a&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;CRUD snippet from the tutorial&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Topics covered include user sign up, login with PassportJS, installing and creating basic tables in PostgreSQL, issuing queries using the Sequelize ORM, what a middleware is and implementing user access control using middleware, form validation, how to divide your views using pug mixins and more.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;a href="https://getbuzz.io/c/learning-expressjs/stories/Learn-how-to-implement-form-validation-and-re-rendering-forms-with-errors-3046248441"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---ZARRaX1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8pvryfmwtn11sxg98yx8.png" alt="Implementing form validations - snippet from tutorial"&gt;&lt;/a&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Implementing form validations - snippet from the tutorial&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Tutorial site with videos split into 28 lessons
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://getbuzz.io/c/learning-expressjs/stories/Learn-how-to-develop-a-NodeJS-application-4007962439"&gt;Here is more content about this tutorial&lt;/a&gt;. If you liked the tutorial, join our Learning Express group free for updates, Q&amp;amp;A, source code and more: &lt;a href="https://getbuzz.io/o/learning-expressjs/u/join-open-access"&gt;https://getbuzz.io/o/learning-expressjs/u/join-open-access&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  I believe learning should be free and fast.
&lt;/h2&gt;

&lt;p&gt;Fast as in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There are no enrollment hops until you reach a course. It starts immediately, online.&lt;/li&gt;
&lt;li&gt;Videos make their point right away. They are short and concise.&lt;/li&gt;
&lt;li&gt;And Fun: Learning must be fun, e.g. not solitary but a social activity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For these reasons I am building &lt;a href="https://getbuzz.io/discover"&gt;Tech Buzz&lt;/a&gt;, a site for learning tech fast and free, - now focusing on tech areas towards building an online business.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update: Launching an online software service shouldn't be hard.
&lt;/h2&gt;

&lt;p&gt;So I took this tutorial some steps further to build &lt;a href="https://saasbox.net"&gt;SaaSBox&lt;/a&gt;. It lets you launch an online web application / SaaS about 4 weeks faster.&lt;/p&gt;

</description>
      <category>node</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>OK we have to have a title then.</title>
      <dc:creator>Bahadir Balban</dc:creator>
      <pubDate>Tue, 10 Oct 2017 16:25:50 +0000</pubDate>
      <link>https://dev.to/bahadirbalban/ok-we-have-to-have-a-title-then-6kg</link>
      <guid>https://dev.to/bahadirbalban/ok-we-have-to-have-a-title-then-6kg</guid>
      <description></description>
      <category>cpp</category>
    </item>
  </channel>
</rss>
