AWS. Storing and displaying the profile picture of users - angularjs

I have a requirement of storing andd displaying the profile picture of my users. So I used the S3.upload function in my nodeJs backend to store the image.
And after the image is stored I stored the link in database to fetch it using ng-source in my view. It worked but the link got expired after few hours and did not work. Below is the code for my upload. Is there any solution in how to do this or any other better way to do this.
var body = fs.createReadStream(file.file.path);
//Upload the photo to AWS
s3.upload({Body: body}, function (err, data) {
if (err) {
res.sendStatus(500);
}
if (data) {
//getSignedUrl and Store it in Database
var AWS = require('aws-sdk');
var url = req.params.doctorId + "/Images/" + fileName;
var s3 = new AWS.S3()
,params = {Bucket: S3Bucket, Key:url };
s3.getSignedUrl('getObject', params, function (err, url) {
if (err || url == null) res.status(500).send({msg: "amazon s3 error"});
else if (url) {
if(req.body.picture == 1) {
User.findByIdAndUpdate(req.params.doctorId, {$set: {'FileName.profilePicture': url}},
function (err, doc) {
if (err)
res.sendStatus(500);
else
res.send({url: url});
});

This is because you're getting the URL from a signed URL and signed URLs expire by design.
From Share an Object with Others on AWS docs:
All objects by default are private. Only the object owner has permission to access these objects. However, the object owner can optionally share objects with others by creating a pre-signed URL, using their own security credentials, to grant time-limited permission to download the objects.
It seems like you're not exactly storing "secret" resources here that access has to be granted to, then the best approach here is store the image publicly. This is trivial to do and you simply have to set the ACL to public-read when you call PutObject or upload. That way you'll know the URL for the object without actually having to retrieve it:
https://s3-[region].amazonaws.com/[bucket]/[file]
This is what your upload statement would look like then:
s3.upload({ Body: body, ACL: 'public-read' }, function (err, data) {

Related

AWS JS SDK: How do I access GameLift data from a subaccount / another role using the root IAM account?

I'm not too familiar with the terms, so please bear with me.
I'm working on a CMS site using react. We've already got logon via AWS Cognito in place, and we used to have a page that displays GameFleet data.
However, the Aliases and Fleets have been moved to a subaccount:
And as such the GameFleet page is empty.
I've initially overcome this problem by creating an IdentityPool (and roles) for the DevRole subaccount, as the CMS retrieves the GameFleet data via the following code:
componentDidMount() {
AWS.config.region = REGION;
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: IDENTITY_POOL_ID // <--- Changed this to new IdentityPoolId
});
AWS.config.credentials.get(function(err) {
if (err) console.log(err);
else console.log(AWS.config.credentials);
});
await this.requestGameLiftData();
};
requestGameLiftData = async () => {
const gamelift = new AWS.GameLift();
try {
const aliasData = await new Promise((resolve, reject) => {
gamelift.listAliases({}, function(err, data) {
if (err) { reject("Aliases failed");}
else { resolve(data); }
});
});
} catch (error) {
console.log(error);
}
};
But the problem now is that there is a new subaccount, one I don't have access to, and I can foresee that new subaccounts might be created which won't have the necessary IdentityPoolId required for my approach.
I've been told accessing the subaccount GameLift data from the root account should be possible, but I'm not sure how. I've been looking at the IAM page under the main account, but there doesn't seem to be anything there that could point to the subaccounts.
Am I missing anything?
You need to use AWS Assume roles functionality here using which your primary account can assume role of secondary account and get temporary credentials of sub-account which can be used to pull the data from sub-account from primary account.
https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html

Get users AD details when logged into Outlook Web Addin

Im still battleing with trying to pull down the details of the logged in (Outlook) user within the add in im developing.
I have exploered the EWS service but, as far as I cant tell, the functions I need are not available so I have started looking at the Outlook REST API.
I can get very basic user details with the following call:
function sendFindPersonRequest() {
//get auth token for Graph
Office.context.mailbox.getCallbackTokenAsync({ isRest: true }, function (result) {
if (result.status === "succeeded") {
var accessToken = result.value;
console.log('REST Access Token : ' + accessToken);
// Use the access token.
getCurrentItem(accessToken);
} else {
// Handle the error.
}
});}
function getCurrentItem(accessToken) {
// Construct the REST URL to the current item.
// Details for formatting the URL can be found at
// https://learn.microsoft.com/previous-versions/office/office-365-api/api/version-2.0/mail-rest-operations#get-messages.
var getMessageUrl = Office.context.mailbox.restUrl +
'/v2.0/me/';
$.ajax({
url: getMessageUrl,
dataType: 'json',
headers: { 'Authorization': 'Bearer ' + accessToken }
}).done(function (item) {
// Message is passed in `item`.
var subject = item.displayName;
console.log('item subject: ' + subject);
}).fail(function (error) {
// Handle error.
});
}
But this doesnt pass any more than Alias, DisplayName and Emailaddress.
#odata.context: "https://outlook.office365.com/api/v2.0/$metadata#Me"
#odata.id: "https://outlook.office365.com/api/v2.0/Users('')"
Alias: "Joe.Bloggs"
DisplayName: ""
EmailAddress: "Joe.Bloggs#emailhere.co.uk"
Id: "baf52ae4-............"
MailboxGuid: "257f3fe1-6.............."
Im looking to get extendeddetails such as Jobtitle, OfficeAddress etc (which are standard AD fields).
I have looked at the GetUser method as well but that returns the same. I really dont want to go down Graph route and it feels that I am missing something as really expect those other fields to be there.
Has any one else used this to better affect?
Thanks
I didn't see where we can create extensions for a user based on Office 365 Data Extensions and Outlook Extended Properties.
And Microsoft.OutlookServices.User also doesn't have such properties as Jobtitle, OfficeAddress etc.
When I tried to use the OData $select query parameter like:
https://outlook.office365.com/api/v2.0/me?$select=DisplayName,Jobtitle,OfficeAddress
It will give an error: "Could not find a property named 'Jobtitle' on type 'Microsoft.OutlookServices.User'."
I'm afraid that what you want is not available in Outlook REST API. You should use Microsoft Graph API or AAD Graph API instead.
Update:
We can use GET https://outlook.office365.com/api/v2.0/me/people?$search="" to find the person's information.

JWT Authentication in Google Cloud Functions

I'm having trouble troubleshooting the cause for a 403 response from the Google Dataflow API while called using the module "googleapis" inside a Google Cloud Function.
The code works when run on my PC using the same code that is being run on Cloud Functions.
The JWT .json file is being retrieved from an object stored on a Google Storage bucket.
The code looks like this:
...
return getToken(). //Retrieves the JWT Client from Google Storage
then(function (jwtToken) {
console.log("Token: ", JSON.stringify(jwtToken));
return dataFlowList({
projectId: adc.projectId,
auth: jwtToken,
filter: "TERMINATED"
}).then(list => filterDataflowJobList(list))
...
Here the getToken function:
...
let storage: CloudStorage.Storage = CloudStorage({
projectId: adc.projectId
});
var bucket: CloudStorage.Bucket = storage.bucket(bucketName);
var bucketGetFiles = PromiseLab.denodeify(bucket.getFiles);
var stream = bucket.file(jwtJsonFileName).createReadStream();
return toString(stream)
.then(function (msg) {
var jsonJwt = JSON.parse(msg);
var jwtClient = new google.auth.JWT(
jsonJwt.client_email,
null,
jsonJwt.private_key,
['https://www.googleapis.com/auth/cloud-platform'], // an array of auth scopes
null
);
return jwtClient;
}).catch(function (error) {
console.log("Error while trying to retrieve JWT json");
throw error;
})
}
...
I'm based in EU and Cloud Functions are US-bound, could that be the case?
Dataflow jobs are also run in US
While running on Google Function, the authentication retrieval method I'm using is not retrieving the projectId, hence the unauthorized.
async function getADC() {
// Acquire a client and the projectId based on the environment. This method looks
// for the GCLOUD_PROJECT and GOOGLE_APPLICATION_CREDENTIALS environment variables.
const res = await auth.getApplicationDefault();
let client = res.credential;
// The createScopedRequired method returns true when running on GAE or a local developer
// machine. In that case, the desired scopes must be passed in manually. When the code is
// running in GCE or a Managed VM, the scopes are pulled from the GCE metadata server.
// See https://cloud.google.com/compute/docs/authentication for more information.
if (client.createScopedRequired && client.createScopedRequired()) {
// Scopes can be specified either as an array or as a single, space-delimited string.
const scopes = ['https://www.googleapis.com/auth/cloud-platform'];
client = client.createScoped(scopes);
}
return {
client: client,
projectId: res.projectId
}
}
I discovered it by looking at the Header request in the error log, it was in the form of: url: 'https://dataflow.googleapis.com/v1b3/projects//jobs' (notice the double "//" between projects and jobs.

Importing inside a website a watson conversation chat

I'm implementing a watson conversation chat, now i'm wondering, how i can import this chat in a existing website?
any helps?
You can see one example conversation-simple in Nodejs and Conversation-with-discovery in Java.
This repository it is from IBM Developers.
This example show one example how to call the API and has some front-end for show the conversation flow and Watson understands, all you have to know how to use Watson, context variables, intents, entities, etc.
In this case, you call conversation API with Service Credentials and Workspace_id from your Conversation created inside IBM Bluemix:
Example to call and invoke the result with Javascript language (nodejs):
var conversation = new Conversation({
// If unspecified here, the CONVERSATION_USERNAME and CONVERSATION_PASSWORD env properties will be checked
// username: '<username>', paste the Service Credentials here or paste in env archive
// password: '<password>',
url: 'https://gateway.watsonplatform.net/conversation/api',
version_date: '2016-10-21',
version: 'v1'
});
// Endpoint to be call from the client side
app.post('/api/message', function(req, res) {
var workspace = process.env.WORKSPACE_ID || '<workspace-id>'; //workspace id can be check inside Conversation Service, click View details
if (!workspace || workspace === '<workspace-id>') {
return res.json({
'output': {
'text': 'The app has not been configured with a <b>WORKSPACE_ID</b> environment variable.' //error if workspace_id is not set
}
});
}
var payload = {
workspace_id: workspace,
context: req.body.context || {},
input: req.body.input || {}
};
// Send the input to the conversation service
conversation.message(payload, function(err, data) {
if (err) {
return res.status(err.code || 500).json(err);
}
return res.json(updateMessage(payload, data));
});
});
You can use other languages (Python, curl, Java) see this Documentation.
Check the example here running.

Using passport-facebook without Mongoose User (No Mongo in the MEAN stack)

I'm very new to the MEAN stack, and this might seem to be very naive or wrong approach, but I want to ask that when we authenticate using passport-facebook strategy, using the following code:
var FacebookStrategy = require('passport-facebook').Strategy;
var User = require('../models/user');
var fbConfig = require('../fb.js');
module.exports = function(passport) {
passport.use('facebook', new FacebookStrategy({
clientID : fbConfig.appID,
clientSecret : fbConfig.appSecret,
callbackURL : fbConfig.callbackUrl
},
// facebook will send back the tokens and profile
function(access_token, refresh_token, profile, done) {
console.log('profile', profile);
// asynchronous
process.nextTick(function() {
// find the user in the database based on their facebook id
User.findOne({ 'id' : profile.id }, function(err, user) {
// if there is an error, stop everything and return that
// ie an error connecting to the database
if (err)
return done(err);
// if the user is found, then log them in
if (user) {
return done(null, user); // user found, return that user
} else {
// if there is no user found with that facebook id, create them
var newUser = new User();
// set all of the facebook information in our user model
newUser.fb.id = profile.id; // set the users facebook id
newUser.fb.access_token = access_token; // we will save the token that facebook provides to the user
newUser.fb.firstName = profile.name.givenName;
newUser.fb.lastName = profile.name.familyName; // look at the passport user profile to see how names are returned
//newUser.fb.email = profile.emails[0].value; // facebook can return multiple emails so we'll take the first
// save our user to the database
newUser.save(function(err) {
if (err)
throw err;
// if successful, return the new user
return done(null, newUser);
});
}
});
});
}));
};
I don't need to store the user information in any data store. I want to store the token only for the time the user is logged into my web application, basically I don't have the need to use Mongo, because all the data that will be displayed in the web application will come from Facebook api, for example the posts for a profile, the number of likes on a particular posts etc. I don't need to have a backend as such, because if I store the data in any data store such as Mongo, the next time the user login then the data will be stale (in a way the Facebook api is kind of my backend), and I also want that the updates for information on any posts done on Facebook should be updated realtime on my web application for e.g. if someone likes a post on the actual Facebook page the number of likes on my web application should also be updated in realtime, so it seems unnecessary to first bring the data from the Facebook SDK and then store it in Mongo, why not just give it to the controller and from there the view can present the data. If my approach is wrong please do correct me.
So basically every time the user logs in an access token is created and used for that session, when the user logs out the access token is destroyed and so completely eliminates the need for storing the token and any data that is brought in using the Facebook SDK.
Replace the function call
User.findOne({ 'id' : profile.id }, function(err, user) {
With facebook sdk authentication call and return the user object when it's validated.
return done(null, user);
Please refer...
https://github.com/jaredhanson/passport-facebook
you need to create a new user template in the model folder. I have created the following: user.js
var facebook = module.exports.facebook = {
id : String,
token : String,
email : String,
name : String
}
and then change the passport.serializeUser and passport.deserializeUser functions.
passport.serializeUser(function(user, done) {
done(null, user.facebook.id);
});
// used to deserialize the user
//passport.deserializeUser(function(id, done) {
passport.deserializeUser(function(id, done) {
done(null, { id: User.facebook.id, token: User.facebook.token, name: User.facebook.name, email: User.facebook.email})
});
then the function: process.nextTick(function() {} replace the content by this code :
var newUser = User;
// set all of the facebook information in our user model
newUser.facebook.id = profile.id; // set the users facebook id
newUser.facebook.token = token; // we will save the token that facebook provides to the user
newUser.facebook.name = profile.name.givenName + ' ' + profile.name.familyName; // look at the passport user profile to see how names are returned
newUser.facebook.email = profile.emails[0].value; // facebook can return multiple emails so we'll take the first
return done(null, newUser);
add the line profileFields: ['id', 'displayName', 'photos', 'emails', 'name'] in function passport.use(new FacebookStrategy({}
change the profile.ejs file by removing the local information div and changing the properties <% = user.facebook.id%> to <% = user.id%> and so on in the others.

Resources