Error when importing #aws-sdk/s3-request-presigner in react-native with expo in browser - amazon-web-services

It works in expo IOS, but when I open in browser with expo, the error message occurs with presigner import. Need some help here! Thank you!!
my code:
import { getSignedUrl } from "#aws-sdk/s3-request-presigner";
const data = new GetObjectCommand(bucketParams);
const url = await getSignedUrl(client, data);
(client was declared with no problem in putObject and getObject)

Solved it, inspired by https://github.com/akveo/react-native-ui-kitten/issues/996
In case anyone else runs to the problem.
First:
$ npm i #expo/webpack-config
Second:
Create webpack.config.js in root of app
Last, In webpack.config.js, add the following code:
const createExpoWebpackConfigAsync = require("#expo/webpack-config");
const path = require("path");
module.exports = async function (env, argv) {
const config = await createExpoWebpackConfigAsync(env, argv);
config.module.rules.forEach(r => {
if (r.oneOf) {
r.oneOf.forEach(o => {
if (o.use && o.use.loader && o.use.loader.includes("babel-loader")) {
o.include = [
path.resolve("."),
path.resolve("node_modules/#aws-sdk/s3-request-presigner"),
];
}
});
}
});
return config;
};

Related

Problem with AWS API Gateway websocket- Lambda postToConnection

I've been trying to solve this problem all day, looking everywhere on the web, even in the official AWS documentation, why does this error keep appearing when I try to send a message to the client through this code?
PS. i use SDK v3 with node.js 18
import {
ApiGatewayManagementApiClient,
PostToConnectionCommand,
} from "#aws-sdk/client-apigatewaymanagementapi";
export const handler = async (event) => {
const domain = event.requestContext.domainName;
const stage = event.requestContext.stage;
const connectionId = event.requestContext.connectionId;
const callbackUrl = `https://${domain}/${stage}`;
const client = new ApiGatewayManagementApiClient({ endpoint: callbackUrl });
const requestParams = {
ConnectionId: connectionId,
Data: "Hello!",
};
const command = new PostToConnectionCommand(requestParams);
try {
await client.send(command);
} catch (error) {
console.log(error);
}
return {
statusCode: 200,
};
};
fef17825-58ce-4ca7-8f38-85857f1aef0a Task timed out after 3.01 seconds
i tried any online guide or video, can anyone help me?

export 'encrypt' (imported as 'encrypt') was not found in '#aws-crypto/client-browser'

I am trying to encrypt data using AWS Encryption SDK for javascript(react) in browser but getting this error : export 'encrypt' (imported as 'encrypt') was not found in '#aws-crypto/client-browser'
import { KmsKeyringBrowser, encrypt } from "#aws-crypto/client-browser";
const generatorKeyId = '*********************'
const keyIds = ['**************************']
const keyring = new KmsKeyringBrowser({generatorKeyId,keyIds})
const context = {
stage: 'demo',
purpose: 'simple demonstration app',
origin: 'us-west-2'
}
const encryptData = async (data) => {
const result = await encrypt(keyring,data, { encryptionContext: context })
console.log(result);
}
I have alos tried using buildEncrypt but it is not working. Below is the code :
import { KmsKeyringBrowser, encrypt } from "#aws-crypto/client-browser";
const generatorKeyId = '*********************'
const keyIds = ['**************************']
const keyring = new KmsKeyringBrowser({generatorKeyId,keyIds})
const context = {
stage: 'demo',
purpose: 'simple demonstration app',
origin: 'us-west-2'
}
const encryptData = async (data) => {
const result = await buildEncrypt({encrypt: (keyring,data, { encryptionContext: context })} )
console.log(result);
}
I am unable to find out what I was doing wrong. Any help would be apprecieated. Thankyou

AWS Cognito client SDK v3 returns 'byteLength' of undefined when running Admin disable user command

I am trying to disable users from my node JS backend using the AWS SDK v3. everything works normally except for the disable/enable user command.
I have tried everything I know but here is my code snippet:
const aws_creds = {
accessKeyId: process.env.ACCESS_KEY_ID,
secretAccessKey: process.env.SECRET_ACCESS_KEY,
};
const cognitoConfig = {
region: process.env.REGION,
credentials: aws_creds,
};
const cognito_v3 = new CognitoIdentityProviderClient(cognitoConfig);
Then in my route I am running this try / catch block
try {
if (status === "enable") {
const enableUserCommand = new AdminEnableUserCommand(userDetails);
const enableUserResults = await cognito_v3.send(enableUserCommand);
return res.status(200).json(enableUserResults);
}
const disableUserCommand = new AdminDisableUserCommand(userDetails);
const disableUserResults = await cognito_v3.send(disableUserCommand);
return res.status(200).json(disableUserResults);
} catch (err) {
console.log(err);
return res.status(400).json(err);
}
However, the err console log returns this:
TypeError: Cannot read property 'byteLength' of undefined
at Object.fromArrayBuffer (C:\Users\SER-01\Documents\ctr\simsim\simsim-backend\lambdas\simsim-auth\node_modules\#aws-sdk\util-buffer-from\dist\cjs\index.js:6:60)
at castSourceData (C:\Users\SER-01\Documents\ctr\simsim\simsim-backend\lambdas\simsim-auth\node_modules\#aws-sdk\hash-node\dist\cjs\index.js:29:31)
at Hash.update (C:\Users\SER-01\Documents\ctr\simsim\simsim-backend\lambdas\simsim-auth\node_modules\#aws-sdk\hash-node\dist\cjs\index.js:12:26)
at hmac (C:\Users\SER-01\Documents\ctr\simsim\simsim-backend\lambdas\simsim-auth\node_modules\#aws-sdk\signature-v4\dist\cjs\credentialDerivation.js:60:10)
at Object.getSigningKey (C:\Users\SER-01\Documents\ctr\simsim\simsim-backend\lambdas\simsim-auth\node_modules\#aws-sdk\signature-v4\dist\cjs\credentialDerivation.js:32:29)
at SignatureV4.getSigningKey (C:\Users\SER-01\Documents\ctr\simsim\simsim-backend\lambdas\simsim-auth\node_modules\#aws-sdk\signature-v4\dist\cjs\SignatureV4.js:139:39)
at SignatureV4.signRequest (C:\Users\SER-01\Documents\ctr\simsim\simsim-backend\lambdas\simsim-auth\node_modules\#aws-sdk\signature-v4\dist\cjs\SignatureV4.js:98:73)
at async C:\Users\SER-01\Documents\ctr\simsim\simsim-backend\lambdas\simsim-auth\node_modules\#aws-sdk\middleware-signing\dist\cjs\middleware.js:14:22
at async StandardRetryStrategy.retry (C:\Users\SER-01\Documents\ctr\simsim\simsim-backend\lambdas\simsim-auth\node_modules\#aws-sdk\middleware-retry\dist\cjs\defaultStrategy.js:56:46)
at async C:\Users\SER-01\Documents\ctr\simsim\simsim-backend\lambdas\simsim-auth\node_modules\#aws-sdk\middleware-logger\dist\cjs\loggerMiddleware.js:6:22
at async C:\Users\SER-01\Documents\ctr\simsim\simsim-backend\lambdas\simsim-auth\src\routes\auth.js:232:33 {
'$metadata': { attempts: 1, totalRetryDelay: 0 }
}
Any idea why?

How to Get Signed S3 Url in AWS-SDK JS Version 3?

I am following the proposed solution by Trivikr for adding support for s3.getSignedUrl api which is not currently available in newer v3. I am trying to make a signed url for getting an object from bucket.
Just for convenience, the code is being added below:
const { S3, GetObjectCommand } = require("#aws-sdk/client-s3"); // 1.0.0-gamma.2 version
const { S3RequestPresigner } = require("#aws-sdk/s3-request-presigner"); // 0.1.0-preview.2 version
const { createRequest } = require("#aws-sdk/util-create-request"); // 0.1.0-preview.2 version
const { formatUrl } = require("#aws-sdk/util-format-url"); // 0.1.0-preview.1 //version
const fetch = require("node-fetch");
(async () => {
try {
const region = "us-east-1";
const Bucket = `SOME_BUCKET_NAME`;
const Key = `SOME_KEY_VALUE`;
const credentials = {
accessKeyId: ACCESS_KEY_HERE,
secretAccessKey: SECRET_KEY_HERE,
sessionToken: SESSION_TOKEN_HERE
};
const S3Client = new S3({ region, credentials, signatureVersion: 'v4' });
console.log('1'); // for quick debugging
const signer = new S3RequestPresigner({ ...S3Client.config });
console.log('2')
const request = await createRequest(
S3Client,
new GetObjectCommand({ Key, Bucket })
);
console.log('3');
let signedUrl = formatUrl(await signer.presign(request));
console.log(signedUrl);
let response = await fetch(signedUrl);
console.log("Response", response);
}catch(e) {
console.error(e);
}
I successfully create S3Client and signer but on creating request, I get the following error:
clientStack.concat(...).filter is not a function
Anything wrong I am doing?
Please also note that I am using webpack for bundling
Just add my example in TypeScript:
import { S3Client, GetObjectCommand, S3ClientConfig } from '#aws-sdk/client-s3';
import { getSignedUrl } from '#aws-sdk/s3-request-presigner';
const s3Configuration: S3ClientConfig = {
credentials: {
accessKeyId: '<ACCESS_KEY_ID>',
secretAccessKey: '<SECRET_ACCESS_KEY>'
},
region: '<REGION>',
};
const s3 = new S3Client(s3Configuration);
const command = new GetObjectCommand({Bucket: '<BUCKET>', Key: '<KEY>' });
const url = await getSignedUrl(s3, command, { expiresIn: 15 * 60 }); // expires in seconds
console.log('Presigned URL: ', url);
RESOLVED
I ended up successfully making the signed urls by installing the beta versions rather than preview (default) ones

Stripe Error: No signatures found matching the expected signature for payload

I have a stripe webhook that call a Firebase function. In this function I need to verify that this request comes from Stripe servers. Here is the code :
const functions = require('firebase-functions');
const bodyParser = require('body-parser');
const stripe = require("stripe")("sk_test_****");
const endpointSecret = 'whsec_****';
const app = require('express')();
app.use(bodyParser.json({
verify: function (req, res, buf) {
var url = req.originalUrl;
if (url.startsWith('/webhook')) {
req.rawBody = buf.toString()
}
}
}));
app.post('/webhook/example', (req, res) => {
let sig = req.headers["stripe-signature"];
try {
console.log(req.bodyRaw)
let event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
console.log(event);
res.status(200).end()
// Do something with event
}
catch (err) {
console.log(err);
res.status(400).end()
}
});
exports.app = functions.https.onRequest(app);
As mentioned in Stripe Documentation, I have to use raw body to perform this security check.
I have tried with my current code and with :
app.use(require('body-parser').raw({type: '*/*'}));
But I always get this error :
Error: No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe? https://github.com/stripe/stripe-node#webhook-signing
Cloud Functions automatically parses body content of known types. If you're getting JSON, then it's already parsed and available to you in req.body. You shouldn't need to add other body parsing middleware.
If you need to process the raw data, you should use req.rawBody, but I don't think you'll need to do that here.
Here is what is working for me:
add this line:
app.use('/api/subs/stripe-webhook', bodyParser.raw({type: "*/*"}))
(The first argument specifies which route we should use the raw body parser on. See the app.use() reference doc.)
just before this line:
app.use(bodyParser.json());
(it doesn't affect all your operation, just this: '/api/subs/stripe-webhook')
Note: If you are using Express 4.16+ you can replace bodyParser by express:
app.use('/api/subs/stripe-webhook', express.raw({type: "*/*"}));
app.use(express.json());
Then:
const endpointSecret = 'whsec_........'
const stripeWebhook = async (req, res) => {
const sig = req.headers['stripe-signature'];
let eventSecure = {}
try {
eventSecure = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
//console.log('eventSecure :', eventSecure);
}
catch (err) {
console.log('err.message :', err.message);
res.status(400).send(`Webhook Secure Error: ${err.message}`)
return
}
res.status(200).send({ received: true });
}
Here is code which is working for me:
app.use(bodyParser.json({
verify: function (req, res, buf) {
var url = req.originalUrl;
if (url.startsWith('/stripe')) {
req.rawBody = buf.toString();
}
}
}));
And then pass the req.rawBody for verification
stripe.checkWebHook(req.rawBody, signature);
Reference: https://github.com/stripe/stripe-node/issues/341
2 things to note:
pass req.rawBody instead of req.body to constructEvent
const event = stripe.webhooks.constructEvent(
req.rawBody,
sig,
STRIPE_WEBHOOK_SECRET
);
Make sure you're using the correct webhook secret. It's unique per webhook url!
2021 - Solution
I faced that error, and after a lot research I could not figure out the problem easily, but finally I could do it based in my architecture below:
//App.js
this.server.use((req, res, next) => {
if (req.originalUrl.startsWith('/webhook')) {
next();
} else {
express.json()(req, res, next);
}
});
//routes.js
routes.post(
'/webhook-payment-intent-update',
bodyParser.raw({ type: 'application/json' }),
//your stripe logic (Im using a controller, but wherever)
(req, res) => {
stripe.webhooks.constructEvent(...)
}
)
Two big warnings to pay attention:
Make sure to send the req.headers['stripe-signature']
Make sure that your endpointSecret is right, if not it will still saying the same error
Tips:
Test it locally by installing the Stripe CLI: https://stripe.com/docs/webhooks/test
Verify your key on stripe dashboard or you can also make sure if you have the right key by verifying you stripe log as below:
I hope it helps you. :)
// Use JSON parser for all non-webhook routes
app.use(
bodyParser.json({
verify: (req, res, buf) => {
const url = req.originalUrl;
if (url.startsWith('/api/stripe/webhook')) {
req.rawBody = buf.toString();
}
}
})
);
The above code will look fine for the above answers. But even I was made one mistake. After put the same thing I got the same error.
Finally, I've figured it out if you're configured body-parser below the rawBody code then it'll work.
Like this
// Use JSON parser for all non-webhook routes
app.use(
bodyParser.json({
verify: (req, res, buf) => {
const url = req.originalUrl;
if (url.startsWith('/api/stripe/webhook')) {
req.rawBody = buf.toString();
}
}
})
);
// Setup express response and body parser configurations
app.use(express.json());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
Hopefully, it'll help someone.
It is late but will help others
Github answer
const payload = req.body
const sig = req.headers['stripe-signature']
const payloadString = JSON.stringify(payload, null, 2);
const secret = 'webhook_secret';
const header = stripe.webhooks.generateTestHeaderString({
payload: payloadString,
secret,
});
let event;
try {
event = stripe.webhooks.constructEvent(payloadString, header, secret);
} catch (err) {
console.log(`Webhook Error: ${err.message}`)
return res.status(400).send(`Webhook Error: ${err.message}`);
}
switch (event.type) {
case 'checkout.session.completed': {
......
enter code here
If you are trying to add a stripe webhook into your NextJS API Route, here's how to do so (ref):
import initStripe from "stripe";
import { buffer } from "micro";
import { NextApiRequest, NextApiResponse } from "next";
export const config = { api: { bodyParser: false } };
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const stripe = initStripe(process.env.STRIPE_SECRET_KEY||'');
const signature = req.headers["stripe-signature"];
const signingSecret = process.env.STRIPE_WEBHOOK_SECRET || '';
const reqBuffer = await buffer(req);
let event;
try {
event = stripe.webhooks.constructEvent(reqBuffer, signature, signingSecret);
} catch (error: any) {
console.log(error);
return res.status(400).send(`Webhook error: ${error?.message}`);
}
console.log({ event });
res.send({ received: true });
};
export default handler;
This is using buffer from the micro library, in combination with the modifying the default API request to use request's rawbody. In some frameworks (like NextJs), rawBody doesn't come OOTB, hence the workaround of retrieving the rawbody by reqBuffer, which is needed in the stripe.webhooks.constructEvent event.
I was able to obtain data from one webhook but not from a second one: the problem was that the secret key I used was the same as the one used for the first webhook, but I found out that every webhook has a different key, that's way I got that same message.
AWS API Gateway + Lambda (Express.js CRUD) I'm using this for Stripe webhook endpoint and it works for me:
app.use(require('body-parser').text({ type: "*/*" }));
This happened to me when sending a test webhook from the Stripe dashboard after I had renamed a firebase cloud function. All my other functions were working fine. Solved by re-setting in the terminal
firebase functions:config:set stripe.webhook_signature="Your webhook signing secret"
(if you're using that) and redeploying the functions firebase deploy --only functions
On a second occasion I solved the problem by rolling the stripe signature in the stripe dashboard.
Please use this script
app.use(
bodyParser.json({
verify: (req, res, buf) => {
req.rawBody = buf;
},
})
);
My fave was combining two of above great answers.
Then you can use req.rawbody when you construct the event.
Replace "webhook" with whatever route you wish you have a raw body for.
app.use(
"/webhook",
express.json({
verify: (req, res, buf) => {
req.rawBody = buf.toString();
},
})
);
BEFORE
app.use(express.json());
Works well if you are using routes and controllers.
To use raw body in express with a specific endpoint in a seperated middleware, my solution is just enabling router to use express.raw for the webhook endpoint.
-node.js v12
-express.js v4.17.1
export const handleBodyRequestParsing = (router: Router): void => {
router.use('/your_webhook_endpoint', express.raw({ type: '*/*' }))
router.use(express.json({ limit: '100mb' }))
router.use(express.urlencoded({ extended: true }))
}
Here is the Quick Tip which may save your hours !
If you are adding express payment to your exciting express app sometimes you may already pass your request as json in the beginning of application by using express middleware app.use(json()); or any other middleware (Bodyparser for example).
If you are doing that then change that to omit your webhook url
Exmaple:
Assume your payment webhook url is /paments/webhhok
app.use((req, res, next) => {
if (req.originalUrl.includes("/payments/webhook")) {
next();
} else {
express.json()(req, res, next);
}
});
When using Stripe in Express, if you have the following line in your code;
app.use(express.json());
it is going to prevent you from providing the raw body to the Stripe even when you explicitly set "bodyParser.raw", which will throw an error. This was the reason my code failed. Finally sorted it out.
I tried all the solutions above and no one worked, and figured out that the only solution was not to use express at all for this endpoint. you just have to create another http function
export const webhook = functions.https.onRequest(async (req, res) => {
try {
const sig = req.headers['stripe-signature']
const endpointSecret = 'web_secret'
const event = stripe.webhooks.constructEvent(
req.rawBody,
sig,
endpointSecret
)
console.log(event.data.object)
res.status(200).send(event.data.object)
} catch (err) {
console.error('ocorreu um erro', err)
res.status(400).send(`Webhook Error: ${err.message}`)
}
})