directory structure
|_ jwks.json
|_ cube.js
|_ package.json
The cube docs give config for cube.js:
const fs = require("fs");
const jwt = require("jsonwebtoken");
const jwkToPem = require("jwk-to-pem");
const jwks = JSON.parse(fs.readFileSync("jwks.json"));
const _ = require("lodash");
module.exports = {
checkAuth: async (req, auth) => {
const decoded = jwt.decode(auth, { complete: true });
const jwk = _.find(jwks.keys, x => x.kid === decoded.header.kid);
const pem = jwkToPem(jwk);
req.authInfo = jwt.verify(auth, pem);
},
contextToAppId: ({ authInfo }) => `APP_${authInfo.userId}`,
preAggregationsSchema: ({ authInfo }) => "pre_aggregations_${authInfo.userId}"
};
Question: If this is the model used (image below) how does one initialize the process to acquire a token. In other words how does the client go about making the initial call in vanilla Javascript to start the token process using /.well_known/jwks.json?
Cube.js does not support token creation because Cube.js is a microservice for analytics.
You can generate JWT:
In your application
Use auth services (auth0, keycloak, etc.)
P.S There is support for token creation, but it's only for development mode.
Related
Right now I'm tinkering with child_added and child_change as well as limittoLast() to properly understand how event listeners work and how I can extract the newly created value which in this case a new child node.
import * as functions from "firebase-functions";
import * as express from "express";
import * as cors from "cors";
import * as admin from "firebase-admin";
admin.initializeApp();
const bot = express();
bot.use(cors( {origin: true}));
bot.post("/", async function(req, res) {
const telegramText = req.body;
req.body.message &&
req.body.message.chat &&
req.body.message.chat.id &&
req.body.message.from &&
req.body.message.from.first_name;
if (telegramText) {
const chat_id = req.body.message.chat.id;
const first_name = req.body.message.from.first_name;
const receivedMessage = req.body.message.text;
// -NHi9ZWHVqTb-wJd9yh0N - test node
// Define your RTDB Reference
const rtdbReference = admin.database().ref("Sensor MQ7");
rtdbReference.on("child_added", callback =>{
console.log("MQ7", callback.val());
})
const mq7ref = rtdbReference.child("-NHi9IWHVqTb-wJd4yhN/MQ7");
mq7ref.orderByKey().limitToLast(1);
// Fetch the data
const snap = await mq7ref.get();
const snapValue = snap.val();
// Inject snapvalue in the response
return res.status(200).send({
method: "sendMessage",
chat_id,
text: `${first_name}\n${receivedMessage}\n${snapValue}`,
});
}
return res.status(200).send({status: "An error occured"});
});
export const router = functions.https.onRequest(bot);
This is the result of my experimentation and as of now I have very limited understanding of how everything works so I'm learning as I go.
According to my RTDB I'm trying to get latest child node whenever it's added
RTDB
Any help or suggestion is greatly appreciated and if possible, I'd like to request a sample code of where I could start working/repair as I'm very new to firebase as well as NodeJS.
I use gRPC but I have a problem initializing the service in Next.js app.
Goal: Create client service only once in app and use it in getServerSideProps (app doesn't use client-side routing).
For example, we have a service generated with grpc-tools (only available on SSR) and then I just want to initialize it somewhere. At first I thought it can be realized in a custom server.js:
const { credentials } = require('#grpc/grpc-js');
const express = require("express");
const next = require("next");
const { MyserviceClient } = require('./gen/myservice_grpc_pb');
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
// Init & Export
exports.myService = new MyserviceClient(
'http://localhost:3000',
credentials.createInsecure(),
);
(async () => {
await app.prepare();
const server = express();
server.get("*", (req, res) => handle(req, res));
server.listen(process.env.PORT, () => {
console.log(`Listening at http://localhost:${process.env.PORT}`);
});
})();
And then use it on the homepage, for example:
import React from 'react';
const { GetSmthRequest } = require('../gen/myservice_pb');
const { myService } = require('../server.js');
const IndexPage = () => (
<div>
<span>My HomePage</span>
</div>
)
const getServerSideProps = async () => {
const request = new GetSmthRequest();
request.setSomeStuff('random');
myService.getStmh(GetSmthRequest, (err, res) => {
//...
})
return {
props: {
}
}
}
export default IndexPage;
But for some reason it's not possible to initialize the client service in the server.js.
Also I tried doing it with next.config.js:
const { credentials } = require('#grpc/grpc-js');
const { MyserviceClient } = require('./gen/myservice_grpc_pb');
module.exports = {
serverRuntimeConfig: {
myService: new MyserviceClient(
'http://localhost:3000',
credentials.createInsecure(),
),
},
};
This solution works, so I can use the service through serverRuntimeConfig, thereby initializing it only once in the entire application, but when I make a request somewhere using getServerSideProps, I get an error:
Request message serialization failure: Expected argument of type ...
Error explanation: (https://stackoverflow.com/a/50845069/9464680)
That error message indicates that message serialization
(transformation of the message object passed to gRPC into binary data)
failed. This generally happens because the message object doesn't
match the expected message type or is otherwise invalid
Does anyone know why I am getting this error?
It's also interesting to see some examples of using Next.js with grpc-node.
For such a case you can use Node.js global
So I'm basically stuck and been tirelessly looking to get my app running. Long story short, I built a custom app for my store that has a custom form that Post's to a third party API for SMS subcribers. I followed the generic tutorials provided by Shopify, and installed it successfully on our production store. HOWEVER, I am trying to embed a div that is being built by my JS function. I used NGROK to create a tunnel between my local machine, have a server running that deals with OAuth (I'm still testing before I deploy to something like Heroku). I've also check if all dependencies are installed. Now the last bit is that when I embed the div with the correct ID- nothing renders - I tried to use Script Tag API, and/or setting up an APP Proxy with a URL redirect, however I STILL cannot get it to render on my theme. It's just one input to enter a phone number that would POST to that API. If anyone can help explain the best way to go about this - or perhaps a more detailed explanation of using the Script Tags API and how I can include that in my server file so that it can connect to my store would be great. Thank you. I've attached my code (minus the API key) was to what I want to render in case I missed something, and included my server.js code.
FRONT END:
console.log('hello World! heres my app');
var div = document.getElementById('AttApp');
div.innerHTML += '<form id="attentive_form" action="https://api.attentivemobile.com/1/add-subscribers" method="POST"><label>Phone Number</label><input id="phone__input" type="phone" name="phone" value="phone" placeholder="phone" /><button type="submit" class="small" >Phone</button></form>';
document.getElementById('attentive_form').addEventListener('submit', function(event){
event.preventDefault();
var phone = document.getElementById("phone__input").value;
console.log(phone);
var attentiveVisitorId = document.cookie.replace(/(?:(?:^|.*;\s*)__attentive_id\s*=\s*([^;]*).*$)|^.*$/, "$1");
var headers = {
'Authorization': 'API KEY',
'Content-Type': 'application/json'
};
fetch('https://api.attentivemobile.com/1/add-subscribers', {
method: 'POST',
headers: headers,
body: JSON.stringify({"phone": phone , "visitorId": attentiveVisitorId }),
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error); })
});
BACK END:
// Import Koa / Dotenv / Fetch modules
require("isomorphic-fetch");
const Koa = require("koa");
const koaStatic = require("koa-static");
const mount = require("koa-mount");
var bodyParser = require('koa-bodyparser');
const session = require("koa-session");
const cors = require('#koa/cors');
const dotenv = require("dotenv");
// Import Shopify/Koa modules to assist with authentication
const { default: createShopifyAuth } = require("#shopify/koa-shopify-auth");
const { verifyRequest } = require("#shopify/koa-shopify-auth");
// Env Configuration
dotenv.config();
const port = parseInt(process.env.PORT, 10) || 3000;
const { SHOPIFY_API_SECRET_KEY, SHOPIFY_API_KEY } = process.env;
const script_tag = {
"script_tag": {
"event": "onload",
"src": "https://b23bcfd244dc.ngrok.io/main.js"
}
}
// Create server using Koa
const server = new Koa();
server.use(session(server));
server.keys = [SHOPIFY_API_SECRET_KEY];
// Import and use server-side routes
const { router } = require('./server/routes.js');
server.use(router.routes());
server.use(router.allowedMethods());
// Authenticate app with Shopify
server.use(
createShopifyAuth({
apiKey: SHOPIFY_API_KEY,
secret: SHOPIFY_API_SECRET_KEY,
scopes: ["read_products", "write_products"],
afterAuth(ctx) {
const { shop, accessToken } = ctx.session;
ctx.cookies.set("accessToken", accessToken, { httpOnly: false });
ctx.cookies.set("shopOrigin", shop, { httpOnly: false });
ctx.redirect("/");
}
})
);
server.use(verifyRequest());
// Enable CORS (required to let Shopify access this API)
server.use(cors());
// Use module 'koa-bodyparser'
server.use(bodyParser());
// Mount app on root path using compiled Vue app in the dist folder
server.use(mount("/", koaStatic(__dirname + "/public")));
// Start-up the server
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
I also just added write_script_tags in the scope.. will try and see if this works.
I am trying to implement cloud function but getting error if i
require it like this
var storage =require('#google-cloud/storage')();
like this when deploying
var storage = require('#google-cloud/storage');
so i resolved to using it as above but tried uploading a picture i am getting error "TypeError: gcs.bucket is not a function"
const os = require('os');
const path = require('path');
///
exports.onFileChange = functions.storage.object().onFinalize((event) => {
const bucket = event.bucket;
const contentType = event.contentType;
const filePath = event.name;
console.log('Changes made to bucket');
///
if(path.basename(filePath).startsWith('renamed-')){
console.log("File was previously renamed");
return;
}
const gcs = storage({
projectId: 'clfapi'
});
///
const destBucket = gcs.bucket(bucket);
const tmFiilePath = path.join(os.tmpdir(), path.basename(filePath));
const metadata = {contentType: contentType};
///
return destBucket.file(filePath).download({
destination: tmFiilePath
}).then(() => {
return destBucket.upload(tmFiilePath, {
destination: 'renamed-' + path.basename(filePath),
metadata: metadata
})
});
});
The API changed in version 2.x of the Cloud Storage node SDK. According to the documentation, you import the SDK like this:
// Imports the Google Cloud client library
const {Storage} = require('#google-cloud/storage');
Then you can create a new Storage object:
// Creates a client
const storage = new Storage();
Then you can reach into a bucket:
const bucket = storage.bucket()
I set up a Typeform webhook and it's working well.
Now I'm trying to secure it, but I'm stuck in the Validate payload from Typeform section.
I adapted the outlined steps and the Ruby example (and a PHP example that Typeform Helpcenter sent me) to Node (Meteor):
const crypto = require('crypto');
function post() {
const payload = this.bodyParams;
const stringifiedPayload = JSON.stringify(payload);
const secret = 'the-random-string';
const receivedSignature = lodash.get(request, 'headers.typeform-signature', '');
const hash = crypto
.createHmac('sha256', secret)
.update(stringifiedPayload, 'binary')
.digest('base64');
const actualSignature = `sha256=${hash}`;
console.log('actualSignature:', actualSignature);
console.log('receivedSignature:', receivedSignature);
if (actualSignature !== receivedSignature) {
return { statusCode: 200 };
}
// .. continue ..
});
But the actualSignature and receivedSignature never match, I get results like:
actualSignature: sha256=4xe1AF0apjIgJNf1jSBG+OFwLYZsKoyFBOzRCesXM0g=
receivedSignature: sha256=b+ZdBUL5KcMAjITxkpzIFibOL1eEtvN84JhF2+schPo=
Why could this be?
You need to use the raw binary request, it is specified in the docs here
Using the HMAC SHA-256 algorithm, create a hash (using created_token
as a key) of the entire received payload as binary.
Here is an example using express and the body-parser middleware
const crypto = require('crypto');
const express = require("express");
const bodyParser = require('body-parser');
const TYPEFORM_SECRET = 'your-secret';
const app = express();
const port = 3000;
app.use(bodyParser.raw({ type: 'application/json' }));
app.post(`/webhook`, (req, res) => {
const expectedSig = req.header('Typeform-Signature');
const hash = crypto.createHmac('sha256', TYPEFORM_SECRET)
.update(req.body)
.digest('base64');
const actualSig = `sha256=${hash}`;
if (actualSig !== expectedSig) {
// invalid request
res.status(403).send();
return;
}
// successful
res.status(200).send();
});
app.listen(port, () => {
console.log(`listening on port ${port}!`);
});