Upload TLS client certificate to Firebase cloud functions - firebase

I'm trying to figure out if it is possible to upload a TLS client certificate to be used for my cloud functions in firebase. The TLS client certificate is required by a third-party payment solution called Swish.
This is my first firebase project and it seems silly that a small issue like this will render the platform unusable for me..

After some headache and trying I found a quite easy way to solve swish-payments through cloud functions:
Using request-js instead of the built in libraries, I only need to build the options object to use in the request.post() method as following:
const swishOptions = {
url: 'LINK TO SWISH SERVER',
json: true,
pfx: fs.readFileSync('cert.p12'),
passphrase: 'swish',
body: swishRequestBody
}
The cert.p12-file should be placed in the same folder as index.js and will be uploaded together with the functions.
rq.post(swishOptions, (err, res) => {
if (err){
console.log('payment creation error: ' + JSON.stringify(err))
reject(err)
}
if (res){
console.log('Payment-token: ' + res.headers.paymentrequesttoken)
}
});
The body-object should contain all fields specified in the Swish API, use console.log() to read the error-messages from the Swish-server.

Related

Firebase emulator: see outgoing HTTP traffic

I have a Cloud Function that calls to Chargebee. In index.ts:
const chargeBee = new ChargeBee();
...
chargeBee.configure({
site,
api_key: apiKey
});
...
export const finalizeSignup = https.onCall(
async (info: SignupInfo, ctx: CallableContext) => {
const cbCmd = chargeBee.hosted_page.retrieve(info.cbHostedPage);
const callbackResolver = new Promise<any>((resolve, reject) => {
// cbCmd.request returns a Promise that seems to do nothing.
// The callback works, however.
// Resolve/reject the Promise with the callback.
void cbCmd.request((err: any, res: any) => {
if (err) {
reject(err);
}
resolve(res);
});
});
// Calling Promise.resolve subscribes to the Promise.
return Promise.resolve(callbackResolver);
}
);
I am testing this function using the Firebase emulators, started via firebase emulators:start --only functions. Chargebee is responding strangely. They require the domain of their incoming requests to be whitelisted: my first guess is that the domain being used by my locally emulated Cloud Function is not whitelisted on the Chargebee side.
How do I see outgoing HTTP information sent by my locally emulated Cloud Function?
The connection is actually HTTPS, not HTTP.
The emulators provide no functionality to intercept network traffic of any form.
For HTTP: you have to apply your own tooling to monitor the HTTP traffic (ie Wireshark).
For HTTPS: possible to monitor using Wireshark, but impossible to analyze without knowing the SSL key. And in the setup above, where a third-party library is handling the request, there is currently no way to obtain the SSL key. I entered a feature request with Firebase to gauge the interest of developing a way to define an SSL key log when starting the Functions emulator, similar to Chrome. A user only identifying themselves as 'Oscar' told me in a private email that "I've already filed a feature regarding this topic to our engineering team regarding this matter, which will be discussed internally." So that tells us that (1) Firebase is aware that the feature is currently lacking, and (2) there is no progress to report on the feature.

Google Cloud Cloud Function signed url yields 403 SignatureDoesNotMatch

I'm getting a 403 SignatureDoesNotMatch error when trying to load a url generated through:
file.getSignedUrl({
expires: moment()
.add(10, 'minutes')
.format()
})
I've done all the steps outlined in the example, including adding a service account token creator to the App Engine default service account to allow the creation of signed urls:
As an alternative approach to using admin via firebase-functions I tried downloading service account credentials service-account-credentials.json and creating a gcs storage object as suggested here as such:
const { Storage } = require('#google-cloud/storage');
const storage = new Storage({
keyFilename: 'service-account-credentials.json',
projectId: 'project-id',
});
storage.bucket('bucket-id').getFiles({prefix: 'path/to/dir'}).then(files => files.map(file => [same code as above]));
However this still generates SignatureDoesNotMatch urls.
I've followed the github issue related to the matter but I have not been able to find a viable solution. The solution listed by Firebase dev owner #mcdonamp in the issue references using iam.signBlobRequest but I don't know where iam is defined, I only see it here as a property of bucket, with no signBlobRequest method, and here as an HTTP API endpoint.
Seems that despite the doc's claim of Content-Type headers being optional, they are not. As suggested by this SO post and this github issue, adding contentType to the getSignedUrl options argument fixes the issue:
file.getSignedUrl({
action: 'read',
contentType: 'audio/wav',
expires: moment()
.add(10, 'minutes')
.format()
})
Make sure to also include the header when requesting the resource as well.

How to run ElasticSearch on user's devices AND keep ElasticSearch server safe?

Writing a mobile app with Firebase being my backend, also using ES to power my search. I'm completely new to ES.
Suppose each user can publish articles, each of which contains some number of tags, which denotes what this article is about, kind of like questions asked here. Users can search for articles, with tags, and articles containing that tag will be displayed. I manage to do that with Cloud Function, so, the Cloud Function basically looks like this:
exports.articleSearch = functions.https.onRequest((req, res) => {
const { tag } = req.query;
const ElasticSearchConfig = {
uri: '..<my elastic cloud url>/articles/article/_search...',
method: 'GET',
body: ...,
json: true,
auth: {
username: '...<my elastic cloud username>...',
password: '...<my elastic cloud password>...'
}
};
// If succeeds, send results back to user, if not, send error back
request(ElasticSearchConfig).then((results) => ...)
.catch((error) => ...);
});
This works, however, it's a bit slow, because I'm not running ElasticSearch on user's devices, instead, through a cloud function. But if I do run the above code on user's devices, you noticed auth property of ElasticSearchConfig object, I'm basically giving everybody permissions to access and manipulate my ES server. How can I run the above code on user's devices and at the same time, prevent them from reading or writing anything without proper permission?
There's no secure way to do what your asking. Even if it was possible, you don't want that kind of processing client side draining the battery, especially on mobile. Your slow response from cloud functions may be caused from the function entering a timeout state, meaning it hasn't been called in a while.

List-things api using http in AWS-IoT?

I am new to this AWS IoT, i was able to get/update thing shadows using http api (https://endpoint/things/thingName/shadow), provided by AWS IoT, but i want the list of things created under my account. Documentation provides the way of getting list-things using AWS CLI, how can i achieve the same using rest-api ?
I found a solution for this, first i build up custom sdk for AWS IoT, using this link you can build, i selected AWS.IoT and AWS.IoTData and build a sdk. After importing that sdk to your solution, you can query like this :
var iot = new AWS.Iot({
"accessKeyId":"accessKeyId",
"secretAccessKey":"secretAccessKey",
"region":"region"
});
iot.listThings({}, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
You can find the API documentation here

Meteor deploy - MAIL_URL not being set

I recently started deploying a meteor app off of my local machine and it seems that the MAIL_URL property is not being set when deploying to a *.meteor.com domain. No matter what I have tried the email is sent via the default MailGun
What I have tried so far.
Verified that process.MAIL_URL is set and works locally - ensures
that I am setting MAIL_URL correctly
Verified that process.MAIL_URL
is set on *.meteor.com domain by checking meteor logs - ensures that
the process.env settings are being set on *.meteor.com
Tried multiple *.meteor.com domains - ensures it was not a subdomain specific
issue
Tried multiple smtp providers: gmail and Mandrill - ensures
that it was not an issue with the smtp provider
Tried creating a simple app with a simple test email button - ensures problem was not
related to my app code
Nothing works. With the simple app, my code is the following:
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to testmail.";
};
Template.hello.events({
'click input' : function () {
console.log("calling send mail");
Meteor.call('sendEmail',
'xxx#gmail.com',
'xxx#domain.com',
'Hello from Meteor!',
'This is a test of Email.send.');
}
});
}
if (Meteor.isServer) {
// In your server code: define a method that the client can call
Meteor.methods({
sendEmail: function (to, from, subject, text) {
check([to, from, subject, text], [String]);
// Let other method calls from the same client start running,
// without waiting for the email sending to complete.
this.unblock();
Email.send({
to: to,
from: from,
subject: subject,
text: text
});
}
});
Meteor.startup(function () {
// code to run on server at startup
process.env.MAIL_URL = 'smtp://blahblah:token#smtp.mandrillapp.com:587/';
console.log(process.env);
});
}
I am out of ideas at this point. Has anybody else experience this before and what was the resolution? Thanks.
By default meteor deploy can only use mailgun since you can't alter the environmental variables on meteor deploy hosting. Additionally meteor deploy hosting uses a galaxy configuration which takes precedence over environmental variables.
If you take a look at [this file] meteor deploy hosting uses some kind of App configuration that configures it over the environmental variable (see https://github.com/meteor/meteor/blob/devel/packages/email/email.js#L42). This is part of the galaxy configuration engine.
You have to modify the Email package to use a custom smtp server. To do this :
get the files from https://github.com/meteor/meteor/tree/devel/packages/email and place them in a directory in your project /packages/email.
add this package to your meteor project with meteor add email. It should override the default meteor-core package. If it says already using, thats okay.
Modify /packages/email/email.js around line 36 to be:
var smtpPool = makePool("<YOUR CUSTOM MAIL_URL>");
Then you should be good to go. Meteor should use this smtp host instead, even on meteor.com hosting.

Resources