Amazon S3 serving file only to app user in react-native - javascript

I am building a social network in react-native / nodejs and using the S3 amazon service to handle the users personal photos (upload, serve)
But I can't seem to wrap my head around how to serve those images, my question is how do I serve those uploaded images to only the application users and not the whole world ?
At first I tried to explicitly fetch the image myself, this allowed me to directly put the S3 credentials, but it doesn't seem practical.
Is there a way to make every GET call made by an app authorized to fetch from my bucket ?

What you need is S3 signed URLs http://docs.aws.amazon.com/AmazonS3/latest/dev/ShareObjectPreSignedURL.html
Instead of fetching images, create unique signed URLs to this images (with a custom expiration time, say 1 week) and pass those to your application. This way you can close your S3 bucket to the world, but your application will be able to obtain the images with these private links.

Thanks to #sergey I made it to what fits my needs the 'getSignedUrl' method.
Here is the code that worked for me :
import AWS from 'aws-sdk/dist/aws-sdk-react-native';
const credentials = new AWS.Crendentials({ accessKeyId: '', secretAccessKey: ''})
const s3 = new AWS.S3({ credentials, signatureVersion: 'v4', region: ''});
// and there it is.
const url = s3.getSignedUrl('getObject', { Bucket: 'your bucket name', Key: 'the filename'}).
And now each time I loop through an array containing multiple references to my photos, during each loop I create for an item a single pre-signed url that I put in my component.

You can use the new AWS Amplify library to accomplish this: https://github.com/aws/aws-amplify
There is an Auth for getting user credentials and establishing identities, both in an Authenticated and UnAuthenticated state, as well as a Storage component which has public and private access profiles.
Install via npm:
npm install --save aws-amplify-react-native
You will need to link the project if using Cognito User Pools:
react-native link amazon-cognito-identity-js
More info here: https://github.com/aws/aws-amplify/blob/master/media/quick_start.md#react-native-development
Then pull in the modules:
import Amplify, {Auth, Storage} from 'aws-amplify-react-native'
Amplify.configure('your_config_file');
Storage.configure({level: 'private'});
Storage.get('myfile');

Related

Programatically upload html files to a web server with nodejs

I have a discord js bot with tickets system (A system where users can create private channel and ask staff for help). When a channel is deleted, my bot saves all messages and creates html file with messages that were in that channel. I want to upload that file to a web server so users can review it without having to download it, but I am unsure how to do it. The below variable attachment holds the html file/string to be uploaded.
const attachment = await discordTranscripts.createTranscript(channel, {
limit: -1, // Max amount of messages to fetch.
returnType: 'attachment', // Valid options: 'buffer' | 'string' | 'attachment' Default: 'attachment'
fileName: fileName, // Only valid with returnBuffer false. Name of attachment.
minify: true // Minify the result? Uses html-minifier
});
This is quite opinion-based question. There are a lot of ways to do it.
SSH
You can use Node SSH to log into your server via SSH and upload the file.
Rest API
Host a simple and secure Rest API in the server to write the HTML file and call it from your main application.
AWS S3
If you are using AWS, Create an S3 Bucket, make it publicly readable and enable static web hosting. Now you can put your HTML files to your S3 Bucket using AWS-SDK and access them via S3 Bucket Url.
If you are using some other cloud platform like Azure / GCP, Checkout their own storage service.

Trying to access an s3 bucket from my app without a logged in user

I am working on an app using SST, The app uses the ReactStaticSite that SST supports. The app has the ability to log in as a site admin and manage which PDF is loaded into the react app. The issue is that when a non logged in user tries to access the s3 bucket they get an error:
Error: No credentials
at AWSS3Provider.<anonymous> (AWSS3Provider.ts:370:1)
at step (index.ts:58:1)
at Object.next (index.ts:58:1)
at fulfilled (index.ts:58:1)
If I change the config of my Amplify.config Auth property
mandatorySignIn: false
I no longer see this error, instead I see a 403 error from the s3 bucket url.
Ideally I don't just want a public bucket, is there a way to have the react app be authorized to get from the s3 bucket using the SST framework?

Using the AWS javascript SDK, V3, is there a credentials provider chain equivalent?

I'm migrating from V2 to V3 of the javascript SDK for AWS, using NodeJS. Our application needs to check for credentials in a couple places. Previously we used the Credential Provider Chain but I cannot find the equivalent in V3. I need to look in the shared INI file (SharedIniFileCredential) when my script runs locally but the script also runs in kubernetes so (I think) I also need roleAssumerWithWebIdentity. How do I use a credential chain in V3?
The module #aws-sdk/credential-provider-node provides a default credential provider similar to what you're looking for:
It will attempt to find credentials from the following sources (listed in order of precedence):
Environment variables exposed via process.env
SSO credentials from token cache
Web identity token credentials
Shared credentials and config ini files
The EC2/ECS Instance Metadata Service
Here's an example from their page:
const { getDefaultRoleAssumerWithWebIdentity } = require("#aws-sdk/client-sts");
const { defaultProvider } = require("#aws-sdk/credential-provider-node");
const { S3Client, GetObjectCommand } = require("#aws-sdk/client-s3");
const provider = defaultProvider({
roleAssumerWithWebIdentity: getDefaultRoleAssumerWithWebIdentity,
});
const client = new S3Client({ credentialDefaultProvider: provider });

How to use .pem file inside Amazon Lambda to access EC2 instance

I'm currently working on a project that take place inside the AWS environment. I have configure a S3 bucket in order to receive mails (mails are coming from SES but that's not relevant).
What I want to do is to create a Lambda function that will be able to access a EC2 instance and launch a python scripts. So far i have the code below. The problem is that when I created my ec2 instance, I didnt create any username or password to connect via SSH. I only have a .pem file (certificate file) to authenticate to the instance.
I did some research but i couldn't find anything useful.
var SSH = require('simple-ssh');
var ssh = new SSH({
host: 'localhost',
user: 'username',
pass: 'password'
});
ssh.exec('python3.6 path/to/my/python/script.py', {
out: function(stdout) {
console.log(stdout);
}
}).start();
i've been thinking of severals solutions, but i'm not sure at all :
find an SSH library in Javascript that handle .pem file
converting .pem into a String (not secure at all, in my opinion).
maybe create a new ssh user in EC2 ?
Thanks you for your time.
A better option would be to use AWS Systems Manager to remotely run commands on your Amazon EC2 instances.
If you still choose to use simple-ssh then you need to supply an SSH key in config.key when creating your SSH object. You can store the private key in Parameter Store or Secrets Manager and retrieve it within the Lambda. In this case, you should definitely use passwordless SSH (with keypair).

How can I use a customized build of the AWS sdk in ReactJS?

I make a customized build here of the AWS SDK:
https://sdk.amazonaws.com/builder/js/
I can't find any examples of how to use this in ReactJS. Can anyone please point me in the right direction?
I have tried putting this in my index.html
And in my ReactJS code replaced imoprt with var:
//import AWS from 'aws-sdk'
var AWS = require('aws-sdk')
But now my application does not even load - shows only the background image and does not load - absolutely zero shows in the Chrome console - no messages at all.
I can see in the Chrome network console that the custom sdk build is being loaded OK with a status 200 so that seems to be OK.
Can anyone suggest what I need to do please?
thanks
You cannot import a customized build of AWS SDK as a module. You'll need to link it as an external js file in /public/index.html:
<script src="PATH/TO/YOUR/CUSTOM/aws-sdk-{SDK_VERSION}.min.js"></script>
Then, you can access the global variable AWS via window object:
const AWS = window.AWS;
AWS.config.region = "YOUR_BUCKET_REGION";
const bucket = new AWS.S3({
params: {
Bucket: "YOUR_BUCKET_NAME"
}
});
Alternatively, instead of linking to customized SDK builds, you can always npm install aws-sdk and then import individual AWS services as:
const S3 = require("aws-sdk/clients/s3");

Categories