catch error: Node.js + Google Cloud Functions - node.js

please help - can't debug this function, with empty proxy it works, but when i'm using any socks5 proxy (format for ex.: socks5://username:pass#1.2.3.4:1234) - fails, but I don't understand where is a problem, how to debug. Any advice would be appreciated. Thanks :)
package.json
"dependencies": {
"#google-cloud/firestore": "5.0.1",
"make-fetch-happen": "9.1.0"
}
index.js
const fetch = require('make-fetch-happen');
const Firestore = require("#google-cloud/firestore");
const firestore = new Firestore({
projectId: process.env.FIRESTORE_PROJECT_ID,
timestampsInSnapshots: true,
});
async function getSegments(appId, apiKey, proxy) {
const opts = {
headers: {
'Content-Type': 'application/json',
Authorization: `Basic ${apiKey}`
}
}
if (proxy) {
opts['proxy'] = proxy
}
const resp = await fetch(`https://onesignal.com/api/v1/apps/${appId}/segments`, opts)
const data = await resp.json()
return data.segments
}
exports.checkProxy = async (req, res) => {
res.set('Access-Control-Allow-Origin', '*')
if (req.method === 'OPTIONS') {
res.set('Access-Control-Allow-Methods', 'POST')
res.set('Access-Control-Allow-Headers', 'Content-Type')
res.set('Access-Control-Max-Age', '3600')
res.status(204).send('')
} else {
if (!req.body.hasOwnProperty('appIds') || !req.body.appIds || req.body.appIds.length === 0) {
res.status(403).send('appIds is required')
return
}
let resp = []
for (const appId of req.body.appIds) {
const appSnap = await firestore.collection('apps').doc(appId).get()
if (appSnap.empty) {
res.status(404).send('app not found')
return
}
const app = appSnap.data()
try {
const campaignData = await getSegments(app.appId, app.apiKey, app.proxy)
resp.push({error: false, app: app.name, appId: app.id})
} catch (e) {
resp.push({error: e, app: app.name, appId: app.id})
}
}
res.status(200).send(resp)
}
}

The problem was solved simply by updating the make-fetch-happen module to version 10.1+. Thanks to the person who gave me a minus without responding - you made the world a better place dude.

Related

FaunaDB returns empty array (FaunaDB + Netlify + VueJS)

My code is based on the repository - https://github.com/ttntm/recept0r-ts
Code from "\functions\read-all.js":
const faunadb = require('faunadb');
const fnHeaders = require('./_shared/headers.js');
exports.handler = (event, context) => {
const client = new faunadb.Client({
secret: process.env.FAUNA_SECRET,
domain: 'db.fauna.com',
scheme: 'https',
port: '443'
});
const q = faunadb.query;
const headers = { ...fnHeaders };
const origin = event.headers.Origin || event.headers.origin;
headers['Access-Control-Allow-Origin'] = origin ? origin : '*';
return client.query(q.Paginate(q.Match(q.Index('all_users'), false), { size: 500 }))
.then((response) => {
const listRefs = response.data;
const getListDataQuery = listRefs.map(ref => q.Get(ref)); // create new query out of list refs, then query the refs
return client.query(getListDataQuery).then((records) => {
return { statusCode: 200, headers: headers, body: JSON.stringify(records) }
})
})
.catch((error) => {
return { statusCode: 400, headers: headers, body: JSON.stringify(error) }
});
}
Code from "\src\store\modules\data.js":
async readAll({ commit, dispatch, rootGetters })
{
const fn = rootGetters['app/functions'];
const request = await fetch(fn.readAll, { method: 'GET' });
const response = await request.json();
if (response.length > 0) {
commit('SET_ALL_RECIPES', response);
commit('SET_LAST_UPDATED', new Date); }
else {
dispatch('app/sendToastMessage', { text: 'Error loading recipes. Please try again later.', type: 'error' }, { root: true });
return 'error';
}
}
Everything seems to be set. For example, this code works:
client.query(q.CreateCollection({ name: 'someCollection' }))
But can't read any data.
If launch application by "netlify dev" (localhost) - "read-all" returns empty array ("[]").
If launch application by "network" - "read-all" returns default "index.html".
I have no idea what's wrong. Maybe someone give advice...
I found a similar question - Local Netlify function server gives strange response instead of FaunaDB data
Some answer:
"In my experience, one of the most common reasons for this error is a routing problem, which is triggering a 404 response route serving HTML instead of your expected function handler."
This code works:
return client.query(q.Paginate(q.Documents(q.Collection('customers')), { size: 500 }))
.then((response) => {
const listRefs = response.data;
const getListDataQuery = listRefs.map(ref => q.Get(ref)); // create new query out of list refs, then query the refs
return client.query(getListDataQuery).then((records) => {
return { statusCode: 200, headers: headers, body: JSON.stringify(records) }
});
})
.catch((error) => {
return { statusCode: 400, headers: headers, body: JSON.stringify(error) }
});

Clickjacking Issue In Shopify Nextjs App?

I am facing an issue regarding clickjacking prevention. I have implemented authentication and custom headers that contain headers that are requested by Shopify.
ctx.set('Content-Security-Policy', `frame-ancestors https://${ctx.query.shop} https://admin.shopify.com`);
ctx.res.setHeader(
"Content-Security-Policy",
`frame-ancestors https://${ctx.query.shop} https://admin.shopify.com;`
)
local environment headers:
[1]: https://i.stack.imgur.com/XBkW4.png
Production Environment response headers:
[2]: https://i.stack.imgur.com/YkfnA.png
It is working fine in my development environment but is not working in production.
my server.js file
/* eslint-disable #typescript-eslint/no-var-requires */
const dotenv = require('dotenv')
const Koa = require('koa')
const next = require('next')
const { default: createShopifyAuth } = require('#shopify/koa-shopify-auth')
const { verifyRequest } = require('#shopify/koa-shopify-auth')
const { default: Shopify, ApiVersion } = require('#shopify/shopify-api')
const { withSentry } = require('#sentry/nextjs')
const proxy = require('koa-proxy')
const Router = require('#koa/router')
const { checkForNewThemeSupport } = require('./checkfordawntheme')
dotenv.config()
const { PORT } = process.env
const { NODE_ENV } = process.env
const port = parseInt(PORT, 10) || 3000
const dev = NODE_ENV !== 'production'
const app = next({ dev })
const handle = withSentry(app.getRequestHandler())
if (!process.env.NEXT_PUBLIC_SHOPIFY_API_KEY || !process.env.SHOPIFY_API_SECRET_KEY) {
console.error('Missing api keys')
}
const SCOPES = [
'read_products',
'write_products',
'unauthenticated_read_product_listings',
'read_orders',
'read_script_tags',
'write_script_tags',
'read_themes'
]
Shopify.Context.initialize({
API_KEY: process.env.NEXT_PUBLIC_SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET_KEY,
SCOPES,
HOST_NAME: process.env.SHOPIFY_APP_URL.replace(/https:\/\//, ''),
API_VERSION: ApiVersion.October20,
IS_EMBEDDED_APP: true,
SESSION_STORAGE: new Shopify.Session.MemorySessionStorage()
})
// TODO replace this with something serious
const ACTIVE_SHOPIFY_SHOPS = {}
const handleRequest = async (ctx) => {
await handle(ctx.req, ctx.res)
ctx.set('Content-Security-Policy', `frame-ancestors https://${ctx.query.shop} https://admin.shopify.com`);
ctx.res.setHeader(
"Content-Security-Policy",
`frame-ancestors https://${ctx.query.shop} https://admin.shopify.com;`
)
console.log("************* frame ancestor ********* ")
ctx.respond = false
ctx.res.statusCode = 200
}
app.prepare().then(() => {
const server = new Koa()
const router = new Router()
server.keys = [Shopify.Context.API_SECRET_KEY]
// online auth for app/user request
server.use(createShopifyAuth({
accessMode: 'online',
afterAuth(ctx) {
// Online access mode access token and shop available in ctx.state.shopify
const { shop } = ctx.state.shopify
const { host } = ctx.query
// Redirect to app with shop parameter upon auth
ctx.redirect(`/?shop=${shop}&host=${host}`)
}
}))
// offline auth for background tasks
server.use(createShopifyAuth({
accessMode: 'offline',
prefix: '/offline',
async afterAuth(ctx) {
const { shop, accessToken } = ctx.state.shopify
ACTIVE_SHOPIFY_SHOPS[shop] = true
// APP_UNINSTALLED webhook to make sure merchants go through OAuth if they reinstall it
const response = await Shopify.Webhooks.Registry.register({
shop,
accessToken,
path: '/webhooks',
topic: 'APP_UNINSTALLED',
webhookHandler: async (topic, shop) => delete ACTIVE_SHOPIFY_SHOPS[shop]
})
if (!response.success) {
console.error(`Failed to register APP_UNINSTALLED webhook: ${response.result}`)
}
ctx.redirect(`/auth?shop=${shop}`)
}
}))
router.get('/', async (ctx) => {
const { shop } = ctx.query
if (ACTIVE_SHOPIFY_SHOPS[shop] === undefined) {
ctx.redirect(`/offline/auth?shop=${shop}`)
} else {
await handleRequest(ctx)
}
})
router.get('(/_next/static/.*)', handleRequest)
router.get('/_next/webpack-hmr', handleRequest)
router.get('/(.*).js', handleRequest)
router.get('/login', verifyRequest(), handleRequest)
router.get('/register', verifyRequest(), handleRequest)
router.post(
'/webhooks',
async (ctx) => {
try {
await Shopify.Webhooks.Registry.process(ctx.req, ctx.res)
} catch (error) {
console.error(`Failed to process webhook: ${error}`)
}
}
)
router.post(
'/graphql',
verifyRequest({ returnHeader: true }),
async (ctx) => {
await Shopify.Utils.graphqlProxy(ctx.req, ctx.res)
}
)
router.get(
'/checkfor20',
verifyRequest(),
async (ctx) => {
try {
const hasCartAppBlock = await checkForNewThemeSupport(ctx)
ctx.body = JSON.stringify({ hasCartAppBlock })
ctx.status = 200
} catch (error) {
console.error(`Failed to check for theme: ${error}`)
}
}
)
server.use(router.allowedMethods())
server.use(router.routes())
server.use(proxy({
host: process.env.NEXT_PUBLIC_TREEPOINTS_API_URL,
match: /^\/********-api\/\w*/,
map: (path) => path?.split(process.env.NEXT_PUBLIC_TREEPOINTS_API_PROXY_URL)?.[1] || path
}))
// eslint-disable-next-line no-console
server.listen(port, () => console.log(`> Ready on http://localhost:${port}`))
})
App development framework: nextjs
deployment server: Heroku
Any help would be appreciated.

Cannot save email in React.js + Express

So I have a function getProfile(). Inside it I am trying to fetch users from the server using a POST call, however it's throwing a CORS error in its response.
Here is the getProfile:
const getProfile = async () => {
try {
const res = await fetch("http://localhost:5000/dashboard/", {
method: "POST",
headers: {
jwt_token: localStorage.token,
"Content-Type": "application/json",
Accept: "application/json",
},
});
const parseData = await res.json();
setEmail(parseData.email);
console.log("Try success");
console.log(parseData.email);
} catch (err) {
console.log("Try failed");
console.error(err.message);
}
};
if you are handling your nodeServer by your own you need to add CORS package
please check this and follow their docs
https://www.npmjs.com/package/cors
1.install package
2. in your app.js file add following
var cors = require('cors')
app.use(cors())
and change you frontend function getProfile() to following:
const getProfile = async () => {
let token = localStorage.getItem("token");
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Authorization", "bearer" + token);
try {
await fetch("http://localhost:5000/dashboard/", {
method: "POST",
headers: myHeaders,
})
.then((r) => r.json().then((data) => ({ status: r.status, data })))
.then((obj) => obj.status === 200 && console.log("data", obj.data));
} catch (err) {
console.error("Try failed", err.message);
}
};

Axios and Oauth1.0 - 'status: 400, Bad Request'

I'm new on Nodejs and all the modules related with Node. I've been trying to use axios for send a Oauth1.0 Autorization signature, but i'm getting: response: { status: 400, statusText: 'Bad Request', ...}
import { BASE_URL } from '../../../config/config.js';
import axios from 'axios';
import status from 'http-status';
import OAuth from 'oauth-1.0a';
import { createHmac } from 'crypto';
import dotenv from 'dotenv';
dotenv.config();
const CONSUMERKEY = process.env.consumer_key;
const CONSUMERSECRET = process.env.consumer_secret;
const TOKENKEY = process.env.access_token;
const TOKENSECRET = process.env.token_secret;
export const oauth = OAuth({
consumer: {
key: CONSUMERKEY,
secret: CONSUMERSECRET,
},
signature_method: 'HMAC-SHA1',
hash_function(base_string, key) {
return createHmac('sha1', key)
.update(base_string)
.digest('base64')
},
})
export const token = {
key: TOKENKEY,
secret: TOKENSECRET,
}
const doRequest = async (query) => {
const request_data = {
url: `${BASE_URL}`,
method: 'GET',
params: { q: `${query}` },
};
const authHeader = oauth.toHeader(oauth.authorize(request_data, token));
return await axios.get(request_data.url, request_data.params, { headers: authHeader });
};
const searchU = async (term) => {
return await doRequest(`${term}`);
};
export const userS = async (req, res, next) => {
try {
const { query } = req;
const { data } = await searchU(query.q);
const string = JSON.stringify(data);
const Rs = JSON.parse(string);
const response = {
code: 1,
message: 'sucess',
response: Rs
};
res.status(status.OK).send(response);
} catch (error) {
next(error);
if (error.response){
console.log("Response: ");
console.log(error.response);
} else if(error.request){
console.log("Request: ");
console.log(error.request)
} else if(error.message){
console.log("Message: ");
console.log(error.message)
}
}
};
I've been also trying the solution given On this post: but there's no way I can make this work, no idea what i could be doing wron...
When i try the following code (see below), using Request module (which is deprecated) works well, but I really need to do it with Axios...
const request_data = {
url: `${BASE_URL}`,
method: 'GET',
params: { q: `${query}` },
};
const authHeader = oauth.toHeader(oauth.authorize(request_data, token));
request(
{
url: request_data.url,
method: request_data.method,
form: request_data.params,
headers: authHeader,
},
function(error, response, body) {
console.log(JSON.parse(body));
}
)
Any thoughts on what I'm doing wrong on this?? Thank you very much!!
Refer to the following link for the Request Config for Axios. I believe you need to have the query params after the header in the axios.get()
Axios Request Config
Try, the following and see how it goes:-
return await axios.get(request_data.url, { headers: authHeader }, request_data.params);

Auth0 with Electron working in development but not when packaged

Im using Auth0 in an electron app to manage a log-in system. I referenced this tutorial here:
https://auth0.com/blog/securing-electron-applications-with-openid-connect-and-oauth-2/
to get started with using it.
Auth0 has been working great when I've been working in development but for some reason fails after I call "yarn package" to build the app. My electron app used electron-react-boilerplate (https://github.com/electron-react-boilerplate/electron-react-boilerplate).
Here are the important files:
// imports
...
import {
getAuthenticationURL,
refreshTokens,
loadTokens,
logout,
getLogOutUrl,
getProfile,
getResponse,
} from './services/authservice';
export default class AppUpdater {
constructor() {
...
}
}
let mainWindow: BrowserWindow | null = null;
if (process.env.NODE_ENV === 'production') {
const sourceMapSupport = require('source-map-support');
sourceMapSupport.install();
}
if (
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
) {
require('electron-debug')();
}
const installExtensions = async () => {
...
};
const createWindow = async () => {
console.log('now starting the main process');
if (
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
) {
await installExtensions();
}
const RESOURCES_PATH = app.isPackaged
? path.join(process.resourcesPath, 'assets')
: path.join(__dirname, '../assets');
const getAssetPath = (...paths: string[]): string => {
return path.join(RESOURCES_PATH, ...paths);
};
mainWindow = new BrowserWindow({
show: true,
width: 1024,
height: 728,
titleBarStyle: 'hidden', // add this line
frame: false,
//icon: getAssetPath('icon.png'),
webPreferences: {
nodeIntegration: true,
},
});
mainWindow.loadURL(`file://${__dirname}/index.html`);
const devtools = new BrowserWindow();
mainWindow.webContents.setDevToolsWebContents(devtools.webContents);
mainWindow.webContents.openDevTools({ mode: 'detach' });
};
/**
* Add event listeners...
*/
let win = null;
function createAuthWindow() {
destroyAuthWin();
win = new BrowserWindow({
width: 1000,
height: 600,
webPreferences: {
nodeIntegration: false,
enableRemoteModule: false,
},
});
console.log(getAuthenticationURL());
win.loadURL(getAuthenticationURL());
const {
session: { webRequest },
} = win.webContents;
const filter = {
urls: [
'file:///callback*',
],
};
webRequest.onBeforeRequest(filter, async ({ url }) => {
console.log(url);
await loadTokens(url)
.then((res) => {
console.log(res);
})
.catch(console.log);
console.log('from web request');
createWindow();
return destroyAuthWin();
});
win.on('authenticated', () => {
console.log('WE HAVE AUTHENTICATED');
destroyAuthWin();
});
win.on('closed', () => {
win = null;
});
}
function destroyAuthWin() {
if (!win) return;
win.close();
win = null;
}
// logout logic: removed for simplicity
ipcMain.on('profileRequest', (event, arg) => {
//event.reply('profileResponse', getProfile());
event.returnValue = getProfile();
});
const showWindow = async () => {
try {
await refreshTokens();
return createWindow();
} catch (err) {
createAuthWindow();
}
};
this is my auth services file:
let accessToken = null;
let profile = {};
let refreshToken = null;
export function getAccessToken() {
return accessToken;
}
export function getProfile() {
return profile;
}
export function getAuthenticationURL() {
return (
'https://' +
auth0Domain +
'/authorize?' +
'scope=openid%20profile%20offline_access&' +
'response_type=code&' +
'client_id=' +
clientId +
'&' +
'redirect_uri=' +
redirectUri
);
}
export async function refreshTokens() {
const refreshToken = await keytar.getPassword(keytarService, keytarAccount);
if (refreshToken) {
const refreshOptions = {
method: 'POST',
url: `https://${auth0Domain}/oauth/token`,
headers: { 'content-type': 'application/json' },
data: {
grant_type: 'refresh_token',
client_id: clientId,
refresh_token: refreshToken,
},
};
try {
const response = await axios(refreshOptions);
res = response;
accessToken = response.data.access_token;
profile = jwtDecode(response.data.id_token);
} catch (error) {
await logout();
throw error;
}
} else {
throw new Error('No available refresh token.');
}
}
export async function loadTokens(callbackURL) {
console.log('loading tokens:');
console.log(callbackURL);
res = callbackURL;
const urlParts = url.parse(callbackURL, true);
const query = urlParts.query;
console.log(query);
const exchangeOptions = {
grant_type: 'authorization_code',
client_id: clientId,
code: query.code,
redirect_uri: redirectUri,
};
const options = {
method: 'POST',
url: `https://${auth0Domain}/oauth/token`,
headers: {
'content-type': 'application/json',
},
data: JSON.stringify(exchangeOptions),
};
try {
const response = await axios(options);
console.log('from token:');
console.log(response);
res = response;
accessToken = response.data.access_token;
profile = jwtDecode(response.data.id_token);
refreshToken = response.data.refresh_token;
console.log(getProfile());
if (refreshToken) {
await keytar.setPassword(keytarService, keytarAccount, refreshToken);
}
} catch (error) {
await logout();
throw error;
}
}
I have a file in my components folder called "Auth.jsx" which has a "get profile" methods which interacts with the main process to get the profile
const getProfile = () => {
return ipcRenderer.sendSync('profileRequest', true);
};
After I package the electron app, the getProfile method always returns null/undefined.
Here are the auth0 logs:
Auth0 Logs
It shows that there is a successful Login and Exchange.
Finally, here's my webpack file: "webpack.config.main.prod.babel"
/**
* Webpack config for production electron main process
*/
import path from 'path';
import webpack from 'webpack';
import { merge } from 'webpack-merge';
import TerserPlugin from 'terser-webpack-plugin';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import baseConfig from './webpack.config.base';
import CheckNodeEnv from '../scripts/CheckNodeEnv';
import DeleteSourceMaps from '../scripts/DeleteSourceMaps';
import dotenv from 'dotenv';
CheckNodeEnv('production');
DeleteSourceMaps();
const devtoolsConfig =
process.env.DEBUG_PROD === 'true'
? {
devtool: 'source-map',
}
: {};
export default merge(baseConfig, {
...devtoolsConfig,
mode: 'production',
target: 'electron-main',
entry: './src/main.dev.ts',
output: {
path: path.join(__dirname, '../../'),
filename: './src/main.prod.js',
},
optimization: {
minimizer: [
new TerserPlugin({
parallel: true,
}),
],
},
plugins: [
new BundleAnalyzerPlugin({
analyzerMode:
process.env.OPEN_ANALYZER === 'true' ? 'server' : 'disabled',
openAnalyzer: process.env.OPEN_ANALYZER === 'true',
}),
new webpack.EnvironmentPlugin({
NODE_ENV: 'production',
DEBUG_PROD: true,
START_MINIMIZED: false,
/*
other environment variables, including auth0 domain name and clientID
*/
}),
],
/**
* Disables webpack processing of __dirname and __filename.
* If you run the bundle in node.js it falls back to these values of node.js.
* https://github.com/webpack/webpack/issues/2010
*/
node: {
__dirname: false,
__filename: false,
},
});
Im suspecting the problem might have something to do with webpack since it's only the packaged version of the application that doesn't work properly. Im not sure exactly what the problem is, whether is a problem in the code or if I need to specifically change something within my Auth0 dashboard. If you have any suggestions or any ideas on how to debug let me know!
I had the exact same issue! I fixed it by changing the import method for jwt-decode from require to import
import jwtDecode from 'jwt-decode'

Resources