Javascript: API call with Certs - javascript

I have to make API call using 'sync-request' node module using certs (.cert & .pem file) which are given to us. Whenever I am trying to make a call - it gives error message as - Unable to verify the first certificate.
I have tried using agentOptions or importing 'ssl-root-cas' node module. But it gives same above error. I am not sure if, I am passing values correctly or not.
let request = require('sync-request');
let crt_file = fs.readFileSync('someFilePath.cer', ascii);
let pem_file = fs.readFileSync('someFilePath.pem', ascii);
let apiUrl = 'http://localhost:8888/getDetails';
let agentOptions = {
maxCachedSessions: 0,
secureProtocol: 'TLSv1_2_method',
securityOptions: 'SSL_OP_NO_SSLv3',
ciphers: 'ALL',
key: crt_file,
cert: pem_file,
Passphrase: 'London1!'
}
let response = request('GET', apiUrl, agentOptions);
I want to get success response with use of certs. The above agentOptions is something which I googled and tried to include.
NOTE: I do not want to use NODE_TLS_REJECT_UNAUTHORIZED=0

With request node module being deprecated, got provides excellent approach. This works for me.
const got = require('got');
const crypto = require('crypto');
const OAuth = require('oauth-1.0a');
const oauth = OAuth({
consumer: {
key: process.env.CONSUMER_KEY,
secret: process.env.CONSUMER_SECRET
},
signature_method: 'HMAC-SHA1',
hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64')
});
const token = {
key: process.env.ACCESS_TOKEN,
secret: process.env.ACCESS_TOKEN_SECRET
};
const url = 'https://api.twitter.com/1.1/statuses/home_timeline.json';
got(url, {
headers: oauth.toHeader(oauth.authorize({url, method: 'GET'}, token)),
responseType: 'json'
});

Related

Interacting with Oauth1 API in cloudflare worker (Flickr)

I'm needing to interact with the Flickr api from a cloudflare worker, but it's turning out to be exceedingly tricky.
My initial idea was to reach for the oauth1.0a library, but unfortunately it requires being passed a synchronous signature function. This is an issue because I need to use WebCrypto on the worker and it only exposes an asynchronous API.
Are there any other libraries I can use? I've currently spent hours trying to manually craft the request but keep getting errors saying the signature is bad.
This is my current attempt using someone's fork of oauth1.0a that adds support for an async signature function. This currently results in an "invalid_signature" response:
import OAuth from 'oauth-1.0a';
const CALLBACK_URL = "https://localhost:3000/oauth/callback";
const encoder = new TextEncoder();
async function signData(baseString: string, keyString: string) {
return await crypto.subtle.importKey(
'raw',
encoder.encode(keyString),
{ name: 'HMAC', hash: 'SHA-1' },
false,
['sign']
).then(key => {
return crypto.subtle.sign(
"HMAC",
key,
encoder.encode(baseString)
);
}).then(signature => {
let b = new Uint8Array(signature);
// base64 digest
return btoa(String.fromCharCode(...b));
});
}
export async function getRequestToken(consumerKey: string, consumerSecret: string) {
const url = "https://www.flickr.com/services/oauth/request_token";
const token = {
key: consumerKey,
secret: consumerSecret
}
const oauth = new OAuth({
consumer: token,
signature_method: 'HMAC-SHA1',
// #ts-ignore
hash_function: signData,
});
const requestData = {
url,
method: 'GET',
data: {
oauth_callback: CALLBACK_URL
}
};
// #ts-ignore
const authorisedRequest = await oauth.authorizeAsync(requestData, token);
let params = new URLSearchParams();
for (let [key, value] of Object.entries(authorisedRequest)) {
params.append(key, value as string);
}
const response = await fetch(requestData.url + `?${params}`, {
method: requestData.method,
});
const body = await response.text();
const parsedBody = oauth.deParam(body);
return parsedBody;
}

Cannot get the contact attributes of Amazon Connect by aws-sdk Javascript

I am using call recording on Amazon Connect.
I am trying to get the contact attribute of Amazon Connect by using the metadata value of the .wav file on S3 where the conversation was recorded.
This is my Lambda function.
Object.defineProperty(exports, "__esModule", { value: true });
const AWS = require("aws-sdk");
const connect = new AWS.Connect();
const s3 = new AWS.S3();
exports.handler = async (event, context) => {
await Promise.all(event.Records.map(async (record) => {
const bucket = event.Records[0].s3.bucket.name;
const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
var params = {
Bucket: bucket,
Key: key,
};
const metadata = await s3.headObject(params).promise();
console.log(metadata);
const contactid = metadata.Metadata['contact-id'];
const instanceid = metadata.Metadata['organization-id'];
var params = {
InitialContactId: contactid,
InstanceId: instanceid,
};
console.log(params);
const connectdata = await connect.getContactAttributes(params).promise();
console.log(connectdata);
}));
};
This is the JSON value of the .wav file (I hide my personal information).
{
AcceptRanges: 'bytes',
LastModified: 2021-09-01TXX:XX:XX.000Z,
ContentLength: 809644,
ETag: '"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"',
ContentType: 'audio/wav',
ServerSideEncryption: 'aws:kms',
Metadata: {
'contact-id': 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
'aws-account-id': 'XXXXXXXXXXXX',
'organization-id': 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
},
SSEKMSKeyId: 'arn:aws:kms:ap-northeast-1:XXXXXXXXXXXX:key/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
}
However, when I used Connect's getContactAttributes method using aws-sdk, there was no value in the obtained parameters.
Even though the parameter values are certainly included.
console.log(params)
{
InitialContactId: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
InstanceId: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
}
console.log(connectdata)
{ Attributes: {} }
I want to know what {Attributes: {}} stands for.
Is there something wrong with the argument of the getContactAttributes method, or the output method of console.log?
In the first place, can't I get the contact attribute from the metadata of the .wav file?
There may be many mistakes because it is a beginner, but I would like advice for this.
Thanks.
This problem has been self-solved.
The connect.getContactAttributes method seems to get only the value of Attributes in the contact flow. I misunderstood that it was to get the JSON itself sent from the contact flow.
I found that the value of Attributes is set by posting a key-value pair in the "Set contact attributes" block of the Amazon Connect contact flow.

Error in Apollo Server deploy with AWS Lambda

People, how are you? I have a query, I just implemented my API made with apollo server in an AWS Lambda. I used the official documentation as a guide, but I'm noticing that the context handling varies a bit. I have a doubt with the latter, since I made certain changes and everything works fine locally using "serverless offline", but once I deploy it doesn't. Apparently the authentication context that I generate does not finish reaching my query. If someone can guide me a bit with this, I will be very grateful.
This is my API index:
const { ApolloServer, gql } = require('apollo-server-lambda');
const typeDefs = require('./db/schema');
const resolvers = require('./db/resolvers');
const db = require('./config/db');
const jwt = require('jsonwebtoken');
require('dotenv').config({ path: 'variables.env' });
db.conectDB();
// The ApolloServer constructor requires two parameters: your schema
// definition and your set of resolvers.
const server = new ApolloServer({
typeDefs,
resolvers,
playground: {
endpoint: "/graphql"
},
context: ({ event, context }) => {
try {
const token = event.headers['authorization'] || '';
if(token){
context.user = jwt.verify(token.replace('Bearer ',''), process.env.KEY_TOKEN);
}
return {
headers: event.headers,
functionName: context.functionName,
event,
context,
}
} catch (error) {
console.error(error);
}
}
});
exports.graphqlHandler = server.createHandler({
cors: {
origin: '*',
credentials: true,
},
});
This is my query:
getUserByToken: async (_, {}, { context }) => {
if(context)
throw new Error((context ? 'context' : '') + ' ' + (context.user ? 'user' : ''));
let user = await db.findOne('users',{ _id: ObjectId(context.user._id) });
if(user.birthdate)
user.birthdate = user.birthdate.toString();
if(user.password)
user.password = true;
else
user.password = false;
return user;
}
My API response:
API response
From what I can see, you're not calling getUserByToken in your context. Is that correct? So, I'm not sure how you're encountering this error.
Can I give you some pointers?
Connecting to your DB is probably (or it should be) asynchronous. For that, I'd run your code like this:
db.connect()
.then(() => {
... handle your request in here
})
.catch(console.error);
I think you meant to call your getUserByToken in this line:
context.user = jwt.verify(token.replace('Bearer ',''), process.env.KEY_TOKEN);

How to solve 'Access-Control-Allow-Origin' error when trying to access api from localhost

I've seen a lot of topics on this error, but I'm very new to js and apis, so I couldn't really understand much, so I apologize for noob status.
I'm trying to access an api from sportradar. I'm testing it out on a simple react project created from create-react-app and using axios. When I console.log the data I get these errors: https://dzwonsemrish7.cloudfront.net/items/372w3g2b3F141t2P0K1G/Image%202018-09-04%20at%2011.33.38%20AM.png
I guess I can't access it from a local host? here is my function with the request:
getPlayerInfo() {
const apiKey = "my-api-key";
const playerID = "41c44740-d0f6-44ab-8347-3b5d515e5ecf";
const url = `http://api.sportradar.us/nfl/official/trial/v5/en/players/${playerID}/profile.json?api_key=${apiKey}`;
axios.get(url).then(response => console.log(response));
}
If the backend support CORS, you probably need to add to your request this header:
headers: {"Access-Control-Allow-Origin": "*"}
Your code would be like this:
getPlayerInfo() {
const apiKey = "my-api-key";
const playerID = "41c44740-d0f6-44ab-8347-3b5d515e5ecf";
const url = `http://api.sportradar.us/nfl/official/trial/v5/en/players/${playerID}/profile.json?api_key=${apiKey}`;
const config = {
headers: {'Access-Control-Allow-Origin': '*'}
};
axios.get(url,config).then(response => console.log(response));
}
Hope this helps !

In firebase - How to generate an idToken on the server for testing purposes?

I want to test a a cloud function that creates users.
In normal cases, inside the browser i generate an idToken and i send it to server via headers: Authorization : Bearer etcIdToken
But I want to test this function without the browser. In my mocha tests i have:
before(done => {
firebase = require firebase.. -- this is suppose to be like the browser lib.
admin = require admin..
idToken = null;
uid = "AY8HrgYIeuQswolbLl53pjdJw8b2";
admin.auth()
.createCustomToken(uid) -- admin creates a customToken
.then(customToken => {
return firebase.auth() -- this is like browser code. customToken get's passed to the browser.
.signInWithCustomToken(customToken) -- browser signs in.
.then(signedInUser => firebase.auth() -- now i want to get an idToken. But this gives me an error.
.currentUser.getIdToken())
})
.then(idToken_ => {
idToken = idToken_
done();
})
.catch(err => done(err));
})
The error i'm getting is:
firebase.auth(...).currentUser.getIdToken is not a function - getting the idToken like this works on client - and is documented here.
I tried directly with signedInUser.getIdToken(). Same problem:
signedInUser.getIdToken is not a function - not documented. just a test.
I think this is because firebase object is not intended for node.js use like i'm doing here. When signing in - stuff get's saved in browser local storage - and maybe this is why.
But the question still remains. How can i get an idToken inside node.js in order to be able to test:
return chai.request(myFunctions.manageUsers)
.post("/create")
.set("Authorization", "Bearer " + idToken) --- i need the idToken here - like would be if i'm getting it from the browser.
.send({
displayName: "jony",
email: "jony#gmail.com",
password: "123456"
})
am I approaching this wrong? I know that if i can get the idToken it will work. Do i rely need the browser for this? Thanks :)
From Exchange custom token for an ID and refresh token, you can transform a custom token to an id token with the api. Hence, you just have to generate a custom token first from the uid, then transform it in a custom token. Here is my sample:
const admin = require('firebase-admin');
const config = require('config');
const rp = require('request-promise');
module.exports.getIdToken = async uid => {
const customToken = await admin.auth().createCustomToken(uid)
const res = await rp({
url: `https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=${config.get('firebase.apiKey')}`,
method: 'POST',
body: {
token: customToken,
returnSecureToken: true
},
json: true,
});
return res.idToken;
};
L. Meyer's Answer Worked for me.
But, the rp npm package is deprecated and is no longer used.
Here is the modified working code using axios.
const axios = require('axios').default;
const admin = require('firebase-admin');
const FIREBASE_API_KEY = 'YOUR_API_KEY_FROM_FIREBASE_CONSOLE';
const createIdTokenfromCustomToken = async uid => {
try {
const customToken = await admin.auth().createCustomToken(uid);
const res = await axios({
url: `https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=${FIREBASE_API_KEY}`,
method: 'post',
data: {
token: customToken,
returnSecureToken: true
},
json: true,
});
return res.data.idToken;
} catch (e) {
console.log(e);
}
}
curl 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=<FIREBASE_KEY>' -H 'Content-Type: application/json'--data-binary '{"email": "test#test.com","password":"test","returnSecureToken":true}'
If this curl doesn't run, try running the same thing on Postman. It works!

Categories